about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs18
-rw-r--r--compiler/rustc_abi/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs4
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs166
-rw-r--r--compiler/rustc_ast/src/token.rs152
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs6
-rw-r--r--compiler/rustc_ast/src/visit.rs24
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs5
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs1
-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/type_check/mod.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs52
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs23
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs1
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs1
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs3
-rw-r--r--compiler/rustc_data_structures/src/unord.rs5
-rw-r--r--compiler/rustc_driver_impl/messages.ftl2
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs117
-rw-r--r--compiler/rustc_driver_impl/src/session_diagnostics.rs8
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs6
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs11
-rw-r--r--compiler/rustc_expand/src/placeholders.rs2
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs4
-rw-r--r--compiler/rustc_feature/Cargo.toml2
-rw-r--r--compiler/rustc_feature/src/unstable.rs50
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs85
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs55
-rw-r--r--compiler/rustc_index/src/bit_set.rs140
-rw-r--r--compiler/rustc_index_macros/src/newtype.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs27
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/early.rs17
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/tail_expr_drop_order.rs308
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs78
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/creader.rs51
-rw-r--r--compiler/rustc_metadata/src/locator.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs11
-rw-r--r--compiler/rustc_middle/src/middle/region.rs5
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs5
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs28
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/query/keys.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs24
-rw-r--r--compiler/rustc_middle/src/thir.rs34
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs18
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs203
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs27
-rw-r--r--compiler/rustc_mir_build/messages.ftl7
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs20
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs23
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs21
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs18
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs13
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs15
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs93
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs49
-rw-r--r--compiler/rustc_mir_build/src/errors.rs30
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs69
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs220
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs42
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_mir_transform/messages.ftl25
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs1
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs3
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs5
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs4
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs1
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs701
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs1
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs1
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs18
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs12
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs12
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs7
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs26
-rw-r--r--compiler/rustc_parse/messages.ftl7
-rw-r--r--compiler/rustc_parse/src/errors.rs28
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs16
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs4
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs26
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs53
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs50
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_resolve/src/ident.rs14
-rw-r--r--compiler/rustc_session/src/config.rs2
-rw-r--r--compiler/rustc_session/src/options.rs50
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs4
-rw-r--r--compiler/rustc_span/src/edition.rs4
-rw-r--r--compiler/rustc_target/src/callconv/aarch64.rs62
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs1
-rw-r--r--compiler/rustc_target/src/callconv/s390x.rs26
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs177
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs59
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs191
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs35
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs68
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs6
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs2
-rw-r--r--compiler/rustc_type_ir/src/interner.rs11
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs1
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs13
-rw-r--r--library/Cargo.lock4
-rw-r--r--library/alloc/src/boxed.rs6
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/core/src/array/mod.rs34
-rw-r--r--library/core/src/iter/range.rs128
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/marker.rs12
-rw-r--r--library/core/src/net/ip_addr.rs10
-rw-r--r--library/core/src/pin.rs6
-rw-r--r--library/core/tests/iter/traits/step.rs35
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/io/cursor.rs6
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/os/fd/owned.rs21
-rw-r--r--library/std/src/sys/pal/uefi/process.rs68
-rw-r--r--library/std/src/sys/random/arc4random.rs2
-rw-r--r--library/std/src/thread/scoped.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs13
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/vendor.rs47
-rw-r--r--src/bootstrap/src/utils/helpers.rs24
-rwxr-xr-xsrc/ci/run.sh2
-rw-r--r--src/doc/rustc/src/command-line-arguments.md2
-rw-r--r--src/doc/rustdoc/src/write-documentation/documentation-tests.md2
-rw-r--r--src/doc/unstable-book/src/language-features/asm-goto.md4
m---------src/llvm-project0
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs1
-rw-r--r--src/tools/generate-copyright/src/cargo_metadata.rs5
-rw-r--r--src/tools/generate-copyright/src/main.rs149
-rw-r--r--src/tools/generate-copyright/templates/COPYRIGHT-library.html53
-rw-r--r--src/tools/miri/.cargo/config.toml9
-rw-r--r--src/tools/miri/README.md1
-rwxr-xr-xsrc/tools/miri/miri8
-rw-r--r--src/tools/miri/miri-script/src/util.rs4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs7
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs11
-rw-r--r--src/tools/miri/src/concurrency/sync.rs118
-rw-r--r--src/tools/miri/src/concurrency/thread.rs9
-rw-r--r--src/tools/miri/src/diagnostics.rs2
-rw-r--r--src/tools/miri/src/eval.rs8
-rw-r--r--src/tools/miri/src/helpers.rs7
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs42
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs39
-rw-r--r--src/tools/miri/src/lib.rs3
-rw-r--r--src/tools/miri/src/machine.rs21
-rw-r--r--src/tools/miri/src/math.rs164
-rw-r--r--src/tools/miri/src/provenance_gc.rs20
-rw-r--r--src/tools/miri/src/shims/extern_static.rs65
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs26
-rw-r--r--src/tools/miri/src/shims/unix/android/thread.rs26
-rw-r--r--src/tools/miri/src/shims/unix/linux/eventfd.rs201
-rw-r--r--src/tools/miri/src/shims/unix/linux/sync.rs72
-rw-r--r--src/tools/miri/src/shims/unix/linux/syscall.rs28
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs60
-rw-r--r--src/tools/miri/src/shims/unix/sync.rs90
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs23
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs51
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs9
-rw-r--r--src/tools/miri/src/shims/windows/thread.rs10
-rw-r--r--src/tools/miri/src/shims/x86/aesni.rs19
-rw-r--r--src/tools/miri/src/shims/x86/gfni.rs18
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs477
-rw-r--r--src/tools/miri/src/shims/x86/sha.rs12
-rw-r--r--src/tools/miri/src/shims/x86/sse42.rs70
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs65
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr41
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs71
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr41
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs96
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr41
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs11
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr14
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs21
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr14
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/write-during-2phase.rs4
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs119
-rw-r--r--src/tools/miri/tests/pass/float.rs14
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/2phase.rs23
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs13
-rw-r--r--src/tools/rustfmt/src/macros.rs2
-rw-r--r--src/version2
-rw-r--r--tests/assembly/s390x-vector-abi.rs322
-rw-r--r--tests/codegen/aarch64-softfloat.rs48
-rw-r--r--tests/crashes/113280.rs16
-rw-r--r--tests/crashes/124350.rs17
-rw-r--r--tests/crashes/124751.rs2
-rw-r--r--tests/crashes/125758.rs26
-rw-r--r--tests/crashes/127351.rs17
-rw-r--r--tests/crashes/127353.rs18
-rw-r--r--tests/crashes/127676.rs8
-rw-r--r--tests/crashes/127742.rs11
-rw-r--r--tests/crashes/130521.rs2
-rw-r--r--tests/run-make/rustc-help/help-v.stdout2
-rw-r--r--tests/run-make/rustc-help/help.stdout2
-rw-r--r--tests/run-make/unstable-feature-usage-metrics/lib.rs9
-rw-r--r--tests/run-make/unstable-feature-usage-metrics/rmake.rs87
-rw-r--r--tests/rustdoc-ui/2024-doctests-checks.rs3
-rw-r--r--tests/rustdoc-ui/2024-doctests-checks.stdout4
-rw-r--r--tests/rustdoc-ui/2024-doctests-crate-attribute.rs3
-rw-r--r--tests/rustdoc-ui/2024-doctests-crate-attribute.stdout4
-rw-r--r--tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs1
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-2024.rs3
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-2024.stdout10
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs3
-rw-r--r--tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout6
-rw-r--r--tests/rustdoc-ui/doctest/merged-ignore-no_run.rs3
-rw-r--r--tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout4
-rw-r--r--tests/rustdoc-ui/doctest/standalone-warning-2024.rs3
-rw-r--r--tests/rustdoc-ui/doctest/standalone-warning-2024.stderr36
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast-2024.rs3
-rw-r--r--tests/rustdoc-ui/doctest/wrong-ast-2024.stdout14
-rw-r--r--tests/ui/asm/x86_64/goto-block-safe.rs23
-rw-r--r--tests/ui/asm/x86_64/goto-block-safe.stderr14
-rw-r--r--tests/ui/async-await/async-closures/fn-exception-target-features.stderr4
-rw-r--r--tests/ui/async-await/async-closures/fn-exception.stderr8
-rw-r--r--tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs14
-rw-r--r--tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr17
-rw-r--r--tests/ui/async-await/async-fn/edition-2015.stderr4
-rw-r--r--tests/ui/async-await/edition-deny-async-fns-2015.stderr18
-rw-r--r--tests/ui/async-await/for-await-passthrough.rs1
-rw-r--r--tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs8
-rw-r--r--tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr8
-rw-r--r--tests/ui/async-await/suggest-switching-edition-on-await.rs8
-rw-r--r--tests/ui/async-await/suggest-switching-edition-on-await.stderr8
-rw-r--r--tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs1
-rw-r--r--tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr20
-rw-r--r--tests/ui/closures/2229_closure_analysis/bad-pattern.stderr13
-rw-r--r--tests/ui/closures/correct-args-on-call-suggestion.rs7
-rw-r--r--tests/ui/closures/correct-args-on-call-suggestion.stderr20
-rw-r--r--tests/ui/codemap_tests/huge_multispan_highlight.rs2
-rw-r--r--tests/ui/confuse-field-and-method/issue-18343.stderr2
-rw-r--r--tests/ui/confuse-field-and-method/issue-2392.stderr14
-rw-r--r--tests/ui/confuse-field-and-method/issue-32128.stderr2
-rw-r--r--tests/ui/confuse-field-and-method/issue-33784.stderr6
-rw-r--r--tests/ui/const-generics/generic_const_exprs/bad-multiply.rs18
-rw-r--r--tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr18
-rw-r--r--tests/ui/const-generics/kind_mismatch.rs1
-rw-r--r--tests/ui/const-generics/kind_mismatch.stderr24
-rw-r--r--tests/ui/consts/const-pattern-irrefutable.rs27
-rw-r--r--tests/ui/consts/const-pattern-irrefutable.stderr73
-rw-r--r--tests/ui/consts/const_in_pattern/incomplete-slice.stderr12
-rw-r--r--tests/ui/coroutine/async_gen_fn.none.stderr2
-rw-r--r--tests/ui/coroutine/async_gen_fn.rs2
-rw-r--r--tests/ui/coroutine/async_gen_fn_iter.rs1
-rw-r--r--tests/ui/coroutine/break-inside-coroutine-issue-124495.rs1
-rw-r--r--tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr14
-rw-r--r--tests/ui/coroutine/const_gen_fn.rs1
-rw-r--r--tests/ui/coroutine/const_gen_fn.stderr4
-rw-r--r--tests/ui/coroutine/gen_block.rs2
-rw-r--r--tests/ui/coroutine/gen_block_is_coro.rs3
-rw-r--r--tests/ui/coroutine/gen_block_is_coro.stderr24
-rw-r--r--tests/ui/coroutine/gen_block_is_fused_iter.rs2
-rw-r--r--tests/ui/coroutine/gen_block_is_iter.rs2
-rw-r--r--tests/ui/coroutine/gen_block_is_no_future.rs2
-rw-r--r--tests/ui/coroutine/gen_block_iterate.rs2
-rw-r--r--tests/ui/coroutine/gen_block_move.fixed2
-rw-r--r--tests/ui/coroutine/gen_block_move.rs2
-rw-r--r--tests/ui/coroutine/gen_block_panic.rs2
-rw-r--r--tests/ui/coroutine/gen_fn.rs2
-rw-r--r--tests/ui/coroutine/gen_fn_iter.rs1
-rw-r--r--tests/ui/coroutine/gen_fn_lifetime_capture.rs1
-rw-r--r--tests/ui/coroutine/other-attribute-on-gen.rs1
-rw-r--r--tests/ui/coroutine/return-types-diverge.rs2
-rw-r--r--tests/ui/coroutine/return-types.rs2
-rw-r--r--tests/ui/coroutine/self_referential_gen_block.rs2
-rw-r--r--tests/ui/diagnostic-width/E0271.rs2
-rw-r--r--tests/ui/diagnostic-width/flag-human.rs2
-rw-r--r--tests/ui/diagnostic-width/long-E0308.rs2
-rw-r--r--tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs2
-rw-r--r--tests/ui/diagnostic-width/non-whitespace-trimming-2.rs2
-rw-r--r--tests/ui/drop/auxiliary/edition-2024-macros.rs1
-rw-r--r--tests/ui/drop/drop_order_if_let_rescope.rs2
-rw-r--r--tests/ui/drop/if-let-rescope-borrowck-suggestions.rs2
-rw-r--r--tests/ui/drop/lint-tail-expr-drop-order-gated.rs6
-rw-r--r--tests/ui/drop/lint-tail-expr-drop-order.rs215
-rw-r--r--tests/ui/drop/lint-tail-expr-drop-order.stderr327
-rw-r--r--tests/ui/drop/tail-expr-drop-order.rs2
-rw-r--r--tests/ui/dyn-star/async-block-dyn-star.rs9
-rw-r--r--tests/ui/dyn-star/async-block-dyn-star.stderr20
-rw-r--r--tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr11
-rw-r--r--tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr11
-rw-r--r--tests/ui/dyn-star/drop.rs7
-rw-r--r--tests/ui/dyn-star/enum-cast.rs7
-rw-r--r--tests/ui/dyn-star/error.rs2
-rw-r--r--tests/ui/dyn-star/error.stderr4
-rw-r--r--tests/ui/dyn-star/float-as-dyn-star.rs16
-rw-r--r--tests/ui/dyn-star/float-as-dyn-star.stderr21
-rw-r--r--tests/ui/dyn-star/upcast.stderr10
-rw-r--r--tests/ui/editions/async-block-2015.rs6
-rw-r--r--tests/ui/editions/async-block-2015.stderr6
-rw-r--r--tests/ui/editions/edition-cstr-2015-2018.rs8
-rw-r--r--tests/ui/editions/edition-cstr-2015-2018.stderr8
-rw-r--r--tests/ui/error-emitter/unicode-output.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-coroutines.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-gen_blocks.rs2
-rw-r--r--tests/ui/generic-associated-types/issue-71176.rs4
-rw-r--r--tests/ui/generic-associated-types/issue-71176.stderr19
-rw-r--r--tests/ui/generics/generics-on-self-mod-segment.rs18
-rw-r--r--tests/ui/generics/generics-on-self-mod-segment.stderr32
-rw-r--r--tests/ui/higher-ranked/builtin-closure-like-bounds.rs1
-rw-r--r--tests/ui/impl-trait/example-calendar.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/late-bound-in-object-assocty.rs2
-rw-r--r--tests/ui/impl-trait/issues/issue-79099.stderr2
-rw-r--r--tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr2
-rw-r--r--tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs1
-rw-r--r--tests/ui/impl-trait/precise-capturing/capturing-implicit.rs1
-rw-r--r--tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr6
-rw-r--r--tests/ui/impl-trait/precise-capturing/external-macro.rs1
-rw-r--r--tests/ui/impl-trait/precise-capturing/foreign-2021.stderr2
-rw-r--r--tests/ui/impl-trait/precise-capturing/migration-note.rs1
-rw-r--r--tests/ui/impl-trait/precise-capturing/migration-note.stderr52
-rw-r--r--tests/ui/impl-trait/precise-capturing/redundant.rs2
-rw-r--r--tests/ui/inline-const/const-block-pat-liveness.rs (renamed from tests/ui/inline-const/const_block_pat_liveness.rs)0
-rw-r--r--tests/ui/inline-const/cross-const-control-flow-125846.rs (renamed from tests/ui/inline-const/cross_const_control_flow.rs)0
-rw-r--r--tests/ui/inline-const/cross-const-control-flow-125846.stderr (renamed from tests/ui/inline-const/cross_const_control_flow.stderr)18
-rw-r--r--tests/ui/inline-const/referencing-local-variables.rs (renamed from tests/ui/inline-const/referencing_local_variables.rs)0
-rw-r--r--tests/ui/inline-const/referencing-local-variables.stderr (renamed from tests/ui/inline-const/referencing_local_variables.stderr)2
-rw-r--r--tests/ui/inline-const/uninit-local.rs (renamed from tests/ui/inline-const/uninit_local.rs)0
-rw-r--r--tests/ui/inline-const/uninit-local.stderr (renamed from tests/ui/inline-const/uninit_local.stderr)2
-rw-r--r--tests/ui/issues/issue-48006.rs4
-rw-r--r--tests/ui/iterators/into-iter-on-boxed-slices-2024.rs1
-rw-r--r--tests/ui/layout/ice-type-error-in-tail-124031.rs3
-rw-r--r--tests/ui/layout/ice-type-error-in-tail-124031.stderr16
-rw-r--r--tests/ui/lazy-type-alias/bad-lazy-type-alias.rs18
-rw-r--r--tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr28
-rw-r--r--tests/ui/lifetimes/tail-expr-in-nested-expr.rs1
-rw-r--r--tests/ui/lifetimes/tail-expr-in-nested-expr.stderr2
-rw-r--r--tests/ui/macros/expr_2021_implicit_in_2024.rs2
-rw-r--r--tests/ui/macros/expr_2021_inline_const.rs4
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.rs4
-rw-r--r--tests/ui/macros/metavar_cross_edition_recursive_macros.rs2
-rw-r--r--tests/ui/match/intended-binding-pattern-is-const.rs10
-rw-r--r--tests/ui/match/intended-binding-pattern-is-const.stderr27
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr20
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr32
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr36
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr34
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr4
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs1
-rw-r--r--tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr10
-rw-r--r--tests/ui/mir/issue-112269.stderr24
-rw-r--r--tests/ui/nll/user-annotations/region-error-ice-109072.rs1
-rw-r--r--tests/ui/nll/user-annotations/region-error-ice-109072.stderr11
-rw-r--r--tests/ui/parser/help-set-edition-ice-122130.stderr2
-rw-r--r--tests/ui/pattern/mut_preserve_binding_mode_2024.rs1
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs1
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs1
-rw-r--r--tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr28
-rw-r--r--tests/ui/pattern/skipped-ref-pats-issue-125058.rs1
-rw-r--r--tests/ui/pattern/skipped-ref-pats-issue-125058.stderr4
-rw-r--r--tests/ui/pattern/usefulness/match-arm-statics-2.stderr12
-rw-r--r--tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr72
-rw-r--r--tests/ui/resolve/const-with-typo-in-pattern-binding.rs45
-rw-r--r--tests/ui/resolve/const-with-typo-in-pattern-binding.stderr78
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs2
-rw-r--r--tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs1
-rw-r--r--tests/ui/rust-2024/prelude2024.rs1
-rw-r--r--tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs1
-rw-r--r--tests/ui/rust-2024/reserved-guarded-strings.rs1
-rw-r--r--tests/ui/rust-2024/reserved-guarded-strings.stderr42
-rw-r--r--tests/ui/sanitizer/cfi/coroutine.rs2
-rw-r--r--tests/ui/simd-abi-checks-s390x.rs174
-rw-r--r--tests/ui/simd-abi-checks-s390x.z10.stderr111
-rw-r--r--tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr111
-rw-r--r--tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr111
-rw-r--r--tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr2
-rw-r--r--tests/ui/specialization/issue-68830-spurious-diagnostics.rs1
-rw-r--r--tests/ui/specialization/issue-68830-spurious-diagnostics.stderr14
-rw-r--r--tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr12
-rw-r--r--tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr4
-rw-r--r--tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs2
-rw-r--r--tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr13
-rw-r--r--tests/ui/thir-print/thir-flat-const-variant.stdout162
-rw-r--r--tests/ui/thir-print/thir-flat.stdout18
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout28
-rw-r--r--tests/ui/thir-print/thir-tree.stdout4
-rw-r--r--tests/ui/trait-bounds/maybe-bound-has-path-args.rs2
-rw-r--r--tests/ui/trait-bounds/maybe-bound-has-path-args.stderr4
-rw-r--r--tests/ui/traits/const-traits/const-closure-parse-not-item.stderr10
-rw-r--r--tests/ui/traits/const-traits/const-opaque.no.stderr15
-rw-r--r--tests/ui/traits/const-traits/const-opaque.rs38
-rw-r--r--tests/ui/traits/const-traits/effects/dont-prefer-param-env-for-infer-self-ty.rs16
-rw-r--r--tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs1
-rw-r--r--tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr16
-rw-r--r--tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs1
-rw-r--r--tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr16
-rw-r--r--tests/ui/traits/issue-78372.rs1
-rw-r--r--tests/ui/traits/issue-78372.stderr24
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs1
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr25
-rw-r--r--tests/ui/traits/span-bug-issue-121414.rs3
-rw-r--r--tests/ui/traits/span-bug-issue-121414.stderr20
-rw-r--r--tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs21
-rw-r--r--tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr86
-rw-r--r--tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs22
-rw-r--r--tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.rs (renamed from tests/crashes/130956.rs)5
-rw-r--r--tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr10
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.rs2
-rw-r--r--tests/ui/unpretty/expanded-exhaustive.stdout2
-rw-r--r--tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.rs1
-rw-r--r--tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr4
-rw-r--r--tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs1
-rw-r--r--tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr4
-rw-r--r--tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs1
-rw-r--r--tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr17
-rw-r--r--triagebot.toml1
460 files changed, 8056 insertions, 3071 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c8d26559728..e4dcf13a84b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1965,9 +1965,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401"
 
 [[package]]
 name = "libc"
-version = "0.2.161"
+version = "0.2.164"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
 
 [[package]]
 name = "libdbus-sys"
@@ -3685,6 +3685,8 @@ version = "0.0.0"
 dependencies = [
  "rustc_data_structures",
  "rustc_span",
+ "serde",
+ "serde_json",
 ]
 
 [[package]]
@@ -3988,6 +3990,7 @@ name = "rustc_metadata"
 version = "0.0.0"
 dependencies = [
  "bitflags 2.6.0",
+ "libc",
  "libloading",
  "odht",
  "rustc_abi",
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index 062447ea03f..d188750bfe1 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -209,6 +209,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
         }
     }
 
+    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
+    where
+        Ty: TyAbiInterface<'a, C>,
+        C: HasDataLayout,
+    {
+        match self.backend_repr {
+            BackendRepr::Vector { .. } => self.size == expected_size,
+            BackendRepr::Memory { .. } => {
+                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
+                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
+                } else {
+                    false
+                }
+            }
+            _ => false,
+        }
+    }
+
     pub fn is_adt<C>(self) -> bool
     where
         Ty: TyAbiInterface<'a, C>,
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 7b6abdf1ea9..2e51753ede6 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -638,7 +638,7 @@ impl AddAssign for Size {
 #[cfg(feature = "nightly")]
 impl Step for Size {
     #[inline]
-    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
         u64::steps_between(&start.bytes(), &end.bytes())
     }
 
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 54e826585d2..888b13efa31 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -457,7 +457,7 @@ impl MetaItemKind {
         tokens: &mut impl Iterator<Item = &'a TokenTree>,
     ) -> Option<MetaItemKind> {
         match tokens.next() {
-            Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
+            Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
                 MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
             }
             Some(TokenTree::Token(token, _)) => {
@@ -605,7 +605,7 @@ impl MetaItemInner {
                 tokens.next();
                 return Some(MetaItemInner::Lit(lit));
             }
-            Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
+            Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
                 tokens.next();
                 return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable());
             }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 811cb0be9f9..61f2f91635d 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -104,8 +104,16 @@ pub trait MutVisitor: Sized {
         walk_use_tree(self, use_tree);
     }
 
+    fn visit_foreign_item(&mut self, ni: &mut P<ForeignItem>) {
+        walk_item(self, ni);
+    }
+
     fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
-        walk_flat_map_item(self, ni)
+        walk_flat_map_foreign_item(self, ni)
+    }
+
+    fn visit_item(&mut self, i: &mut P<Item>) {
+        walk_item(self, i);
     }
 
     fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
@@ -116,10 +124,18 @@ pub trait MutVisitor: Sized {
         walk_fn_header(self, header);
     }
 
+    fn visit_field_def(&mut self, fd: &mut FieldDef) {
+        walk_field_def(self, fd);
+    }
+
     fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
         walk_flat_map_field_def(self, fd)
     }
 
+    fn visit_assoc_item(&mut self, i: &mut P<AssocItem>, ctxt: AssocCtxt) {
+        walk_assoc_item(self, i, ctxt)
+    }
+
     fn flat_map_assoc_item(
         &mut self,
         i: P<AssocItem>,
@@ -153,6 +169,10 @@ pub trait MutVisitor: Sized {
         walk_flat_map_stmt(self, s)
     }
 
+    fn visit_arm(&mut self, arm: &mut Arm) {
+        walk_arm(self, arm);
+    }
+
     fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
         walk_flat_map_arm(self, arm)
     }
@@ -199,6 +219,10 @@ pub trait MutVisitor: Sized {
         walk_foreign_mod(self, nm);
     }
 
+    fn visit_variant(&mut self, v: &mut Variant) {
+        walk_variant(self, v);
+    }
+
     fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
         walk_flat_map_variant(self, v)
     }
@@ -251,6 +275,10 @@ pub trait MutVisitor: Sized {
         walk_attribute(self, at);
     }
 
+    fn visit_param(&mut self, param: &mut Param) {
+        walk_param(self, param);
+    }
+
     fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
         walk_flat_map_param(self, param)
     }
@@ -271,6 +299,10 @@ pub trait MutVisitor: Sized {
         walk_variant_data(self, vdata);
     }
 
+    fn visit_generic_param(&mut self, param: &mut GenericParam) {
+        walk_generic_param(self, param)
+    }
+
     fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
         walk_flat_map_generic_param(self, param)
     }
@@ -287,6 +319,10 @@ pub trait MutVisitor: Sized {
         walk_mt(self, mt);
     }
 
+    fn visit_expr_field(&mut self, f: &mut ExprField) {
+        walk_expr_field(self, f);
+    }
+
     fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
         walk_flat_map_expr_field(self, f)
     }
@@ -311,6 +347,10 @@ pub trait MutVisitor: Sized {
         // Do nothing.
     }
 
+    fn visit_pat_field(&mut self, fp: &mut PatField) {
+        walk_pat_field(self, fp)
+    }
+
     fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
         walk_flat_map_pat_field(self, fp)
     }
@@ -429,16 +469,20 @@ pub fn visit_delim_span<T: MutVisitor>(vis: &mut T, DelimSpan { open, close }: &
     vis.visit_span(close);
 }
 
-pub fn walk_flat_map_pat_field<T: MutVisitor>(
-    vis: &mut T,
-    mut fp: PatField,
-) -> SmallVec<[PatField; 1]> {
-    let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp;
+pub fn walk_pat_field<T: MutVisitor>(vis: &mut T, fp: &mut PatField) {
+    let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_ident(ident);
     vis.visit_pat(pat);
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_pat_field<T: MutVisitor>(
+    vis: &mut T,
+    mut fp: PatField,
+) -> SmallVec<[PatField; 1]> {
+    vis.visit_pat_field(&mut fp);
     smallvec![fp]
 }
 
@@ -459,14 +503,18 @@ fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) {
     vis.visit_span(span);
 }
 
-pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
-    let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
+pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) {
+    let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_pat(pat);
     visit_opt(guard, |guard| vis.visit_expr(guard));
     visit_opt(body, |body| vis.visit_expr(body));
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
+    vis.visit_arm(&mut arm);
     smallvec![arm]
 }
 
@@ -543,11 +591,8 @@ fn walk_foreign_mod<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) {
     items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
 }
 
-pub fn walk_flat_map_variant<T: MutVisitor>(
-    visitor: &mut T,
-    mut variant: Variant,
-) -> SmallVec<[Variant; 1]> {
-    let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
+pub fn walk_variant<T: MutVisitor>(visitor: &mut T, variant: &mut Variant) {
+    let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant;
     visitor.visit_id(id);
     visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
@@ -555,6 +600,13 @@ pub fn walk_flat_map_variant<T: MutVisitor>(
     visitor.visit_variant_data(data);
     visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
     visitor.visit_span(span);
+}
+
+pub fn walk_flat_map_variant<T: MutVisitor>(
+    vis: &mut T,
+    mut variant: Variant,
+) -> SmallVec<[Variant; 1]> {
+    vis.visit_variant(&mut variant);
     smallvec![variant]
 }
 
@@ -685,13 +737,17 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
     vis.visit_span(span);
 }
 
-pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
-    let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
+pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) {
+    let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_pat(pat);
     vis.visit_ty(ty);
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
+    vis.visit_param(&mut param);
     smallvec![param]
 }
 
@@ -950,11 +1006,8 @@ fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCaptu
     }
 }
 
-pub fn walk_flat_map_generic_param<T: MutVisitor>(
-    vis: &mut T,
-    mut param: GenericParam,
-) -> SmallVec<[GenericParam; 1]> {
-    let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
+pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) {
+    let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_ident(ident);
@@ -972,6 +1025,13 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>(
     if let Some(colon_span) = colon_span {
         vis.visit_span(colon_span);
     }
+}
+
+pub fn walk_flat_map_generic_param<T: MutVisitor>(
+    vis: &mut T,
+    mut param: GenericParam,
+) -> SmallVec<[GenericParam; 1]> {
+    vis.visit_generic_param(&mut param);
     smallvec![param]
 }
 
@@ -1054,30 +1114,38 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
     vis.visit_span(span);
 }
 
-pub fn walk_flat_map_field_def<T: MutVisitor>(
-    visitor: &mut T,
-    mut fd: FieldDef,
-) -> SmallVec<[FieldDef; 1]> {
-    let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd;
+pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
+    let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = fd;
     visitor.visit_id(id);
     visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
     visit_opt(ident, |ident| visitor.visit_ident(ident));
     visitor.visit_ty(ty);
     visitor.visit_span(span);
-    smallvec![fd]
 }
 
-pub fn walk_flat_map_expr_field<T: MutVisitor>(
+pub fn walk_flat_map_field_def<T: MutVisitor>(
     vis: &mut T,
-    mut f: ExprField,
-) -> SmallVec<[ExprField; 1]> {
-    let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f;
+    mut fd: FieldDef,
+) -> SmallVec<[FieldDef; 1]> {
+    vis.visit_field_def(&mut fd);
+    smallvec![fd]
+}
+
+pub fn walk_expr_field<T: MutVisitor>(vis: &mut T, f: &mut ExprField) {
+    let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f;
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_ident(ident);
     vis.visit_expr(expr);
     vis.visit_span(span);
+}
+
+pub fn walk_flat_map_expr_field<T: MutVisitor>(
+    vis: &mut T,
+    mut f: ExprField,
+) -> SmallVec<[ExprField; 1]> {
+    vis.visit_expr_field(&mut f);
     smallvec![f]
 }
 
@@ -1331,18 +1399,19 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
     vis.visit_span(inject_use_span);
 }
 
-pub fn walk_flat_map_item<K: WalkItemKind<Ctxt = ()>>(
-    visitor: &mut impl MutVisitor,
-    item: P<Item<K>>,
-) -> SmallVec<[P<Item<K>>; 1]> {
-    walk_flat_map_assoc_item(visitor, item, ())
+pub fn walk_item(visitor: &mut impl MutVisitor, item: &mut P<Item<impl WalkItemKind<Ctxt = ()>>>) {
+    walk_item_ctxt(visitor, item, ())
+}
+
+pub fn walk_assoc_item(visitor: &mut impl MutVisitor, item: &mut P<AssocItem>, ctxt: AssocCtxt) {
+    walk_item_ctxt(visitor, item, ctxt)
 }
 
-pub fn walk_flat_map_assoc_item<K: WalkItemKind>(
+fn walk_item_ctxt<K: WalkItemKind>(
     visitor: &mut impl MutVisitor,
-    mut item: P<Item<K>>,
+    item: &mut P<Item<K>>,
     ctxt: K::Ctxt,
-) -> SmallVec<[P<Item<K>>; 1]> {
+) {
     let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
     visitor.visit_id(id);
     visit_attrs(visitor, attrs);
@@ -1351,6 +1420,27 @@ pub fn walk_flat_map_assoc_item<K: WalkItemKind>(
     kind.walk(*span, *id, ident, vis, ctxt, visitor);
     visit_lazy_tts(visitor, tokens);
     visitor.visit_span(span);
+}
+
+pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> {
+    vis.visit_item(&mut item);
+    smallvec![item]
+}
+
+pub fn walk_flat_map_foreign_item(
+    vis: &mut impl MutVisitor,
+    mut item: P<ForeignItem>,
+) -> SmallVec<[P<ForeignItem>; 1]> {
+    vis.visit_foreign_item(&mut item);
+    smallvec![item]
+}
+
+pub fn walk_flat_map_assoc_item(
+    vis: &mut impl MutVisitor,
+    mut item: P<AssocItem>,
+    ctxt: AssocCtxt,
+) -> SmallVec<[P<AssocItem>; 1]> {
+    vis.visit_assoc_item(&mut item, ctxt);
     smallvec![item]
 }
 
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 3b9edef0615..678f43e3511 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -42,11 +42,86 @@ pub enum BinOpToken {
     Shr,
 }
 
+// This type must not implement `Hash` due to the unusual `PartialEq` impl below.
+#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
+pub enum InvisibleOrigin {
+    // From the expansion of a metavariable in a declarative macro.
+    MetaVar(MetaVarKind),
+
+    // Converted from `proc_macro::Delimiter` in
+    // `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
+    ProcMacro,
+
+    // Converted from `TokenKind::Interpolated` in
+    // `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
+    FlattenToken,
+}
+
+impl PartialEq for InvisibleOrigin {
+    #[inline]
+    fn eq(&self, _other: &InvisibleOrigin) -> bool {
+        // When we had AST-based nonterminals we couldn't compare them, and the
+        // old `Nonterminal` type had an `eq` that always returned false,
+        // resulting in this restriction:
+        // https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment
+        // This `eq` emulates that behaviour. We could consider lifting this
+        // restriction now but there are still cases involving invisible
+        // delimiters that make it harder than it first appears.
+        false
+    }
+}
+
+/// Annoyingly similar to `NonterminalKind`, but the slight differences are important.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
+pub enum MetaVarKind {
+    Item,
+    Block,
+    Stmt,
+    Pat(NtPatKind),
+    Expr {
+        kind: NtExprKind,
+        // This field is needed for `Token::can_begin_literal_maybe_minus`.
+        can_begin_literal_maybe_minus: bool,
+        // This field is needed for `Token::can_begin_string_literal`.
+        can_begin_string_literal: bool,
+    },
+    Ty,
+    Ident,
+    Lifetime,
+    Literal,
+    Meta,
+    Path,
+    Vis,
+    TT,
+}
+
+impl fmt::Display for MetaVarKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let sym = match self {
+            MetaVarKind::Item => sym::item,
+            MetaVarKind::Block => sym::block,
+            MetaVarKind::Stmt => sym::stmt,
+            MetaVarKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
+            MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param,
+            MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
+            MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
+            MetaVarKind::Ty => sym::ty,
+            MetaVarKind::Ident => sym::ident,
+            MetaVarKind::Lifetime => sym::lifetime,
+            MetaVarKind::Literal => sym::literal,
+            MetaVarKind::Meta => sym::meta,
+            MetaVarKind::Path => sym::path,
+            MetaVarKind::Vis => sym::vis,
+            MetaVarKind::TT => sym::tt,
+        };
+        write!(f, "{sym}")
+    }
+}
+
 /// Describes how a sequence of token trees is delimited.
 /// Cannot use `proc_macro::Delimiter` directly because this
 /// structure should implement some additional traits.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[derive(Encodable, Decodable, Hash, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum Delimiter {
     /// `( ... )`
     Parenthesis,
@@ -59,7 +134,34 @@ pub enum Delimiter {
     /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
     /// `$var * 3` where `$var` is `1 + 2`.
     /// Invisible delimiters might not survive roundtrip of a token stream through a string.
-    Invisible,
+    Invisible(InvisibleOrigin),
+}
+
+impl Delimiter {
+    // Should the parser skip these delimiters? Only happens for certain kinds
+    // of invisible delimiters. Ideally this function will eventually disappear
+    // and no invisible delimiters will be skipped.
+    #[inline]
+    pub fn skip(&self) -> bool {
+        match self {
+            Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
+            Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
+            Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
+                true
+            }
+        }
+    }
+
+    // This exists because `InvisibleOrigin`s should be compared. It is only used for assertions.
+    pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
+        match (self, other) {
+            (Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
+            (Delimiter::Brace, Delimiter::Brace) => true,
+            (Delimiter::Bracket, Delimiter::Bracket) => true,
+            (Delimiter::Invisible(_), Delimiter::Invisible(_)) => true,
+            _ => false,
+        }
+    }
 }
 
 // Note that the suffix is *not* considered when deciding the `LitKind` in this
@@ -496,10 +598,11 @@ impl Token {
     /// **NB**: Take care when modifying this function, since it will change
     /// the stable set of tokens that are allowed to match an expr nonterminal.
     pub fn can_begin_expr(&self) -> bool {
+        use Delimiter::*;
         match self.uninterpolate().kind {
             Ident(name, is_raw)              =>
                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
-            OpenDelim(..)                     | // tuple, array or block
+            OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block
             Literal(..)                       | // literal
             Not                               | // operator not
             BinOp(Minus)                      | // unary minus
@@ -510,7 +613,7 @@ impl Token {
             // DotDotDot is no longer supported, but we need some way to display the error
             DotDot | DotDotDot | DotDotEq     | // range notation
             Lt | BinOp(Shl)                   | // associated path
-            PathSep                            | // global path
+            PathSep                           | // global path
             Lifetime(..)                      | // labeled loop
             Pound                             => true, // expression attributes
             Interpolated(ref nt) =>
@@ -520,6 +623,12 @@ impl Token {
                     NtLiteral(..) |
                     NtPath(..)
                 ),
+            OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+                MetaVarKind::Block |
+                MetaVarKind::Expr { .. } |
+                MetaVarKind::Literal |
+                MetaVarKind::Path
+            ))) => true,
             _ => false,
         }
     }
@@ -553,6 +662,14 @@ impl Token {
                     | NtPath(..)
                     | NtTy(..)
                 ),
+            OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+                MetaVarKind::Expr { .. } |
+                MetaVarKind::Literal |
+                MetaVarKind::Meta |
+                MetaVarKind::Pat(_) |
+                MetaVarKind::Path |
+                MetaVarKind::Ty
+            ))) => true,
             _ => false,
         }
     }
@@ -573,6 +690,10 @@ impl Token {
             Lt | BinOp(Shl)             | // associated path
             PathSep                      => true, // global path
             Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
+            OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+                MetaVarKind::Ty |
+                MetaVarKind::Path
+            ))) => true,
             // For anonymous structs or unions, which only appear in specific positions
             // (type of struct fields or union fields), we don't consider them as regular types
             _ => false,
@@ -585,6 +706,9 @@ impl Token {
             OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true,
             Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
             Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
+            OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+                MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
+            ))) => true,
             _ => false,
         }
     }
@@ -641,6 +765,13 @@ impl Token {
                 },
                 _ => false,
             },
+            OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
+                MetaVarKind::Literal => true,
+                MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
+                    can_begin_literal_maybe_minus
+                }
+                _ => false,
+            },
             _ => false,
         }
     }
@@ -656,6 +787,11 @@ impl Token {
                 },
                 _ => false,
             },
+            OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
+                MetaVarKind::Literal => true,
+                MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
+                _ => false,
+            },
             _ => false,
         }
     }
@@ -896,7 +1032,7 @@ impl PartialEq<TokenKind> for Token {
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
 pub enum NtPatKind {
     // Matches or-patterns. Was written using `pat` in edition 2021 or later.
     PatWithOr,
@@ -906,7 +1042,7 @@ pub enum NtPatKind {
     PatParam { inferred: bool },
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
 pub enum NtExprKind {
     // Matches expressions using the post-edition 2024. Was written using
     // `expr` in edition 2024 or later.
@@ -933,7 +1069,7 @@ pub enum Nonterminal {
     NtVis(P<ast::Visibility>),
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
 pub enum NonterminalKind {
     Item,
     Block,
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 0b4bfc0b36a..c6b6addc946 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -24,7 +24,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
 
 use crate::ast::{AttrStyle, StmtKind};
 use crate::ast_traits::{HasAttrs, HasTokens};
-use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
+use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
 use crate::{AttrVec, Attribute};
 
 /// Part of a `TokenStream`.
@@ -484,13 +484,13 @@ impl TokenStream {
             token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
                 DelimSpan::from_single(token.span),
                 DelimSpacing::new(Spacing::JointHidden, spacing),
-                Delimiter::Invisible,
+                Delimiter::Invisible(InvisibleOrigin::FlattenToken),
                 TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
             ),
             token::Interpolated(ref nt) => TokenTree::Delimited(
                 DelimSpan::from_single(token.span),
                 DelimSpacing::new(Spacing::JointHidden, spacing),
-                Delimiter::Invisible,
+                Delimiter::Invisible(InvisibleOrigin::FlattenToken),
                 TokenStream::from_nonterminal_ast(&nt).flattened(),
             ),
             _ => TokenTree::Token(token.clone(), spacing),
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index c121e7711ee..0302c9fa7f8 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -463,13 +463,6 @@ impl WalkItemKind for ItemKind {
     }
 }
 
-pub fn walk_item<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    item: &'a Item<impl WalkItemKind<Ctxt = ()>>,
-) -> V::Result {
-    walk_assoc_item(visitor, item, ())
-}
-
 pub fn walk_enum_def<'a, V: Visitor<'a>>(
     visitor: &mut V,
     EnumDef { variants }: &'a EnumDef,
@@ -931,7 +924,22 @@ impl WalkItemKind for AssocItemKind {
     }
 }
 
-pub fn walk_assoc_item<'a, V: Visitor<'a>, K: WalkItemKind>(
+pub fn walk_item<'a, V: Visitor<'a>>(
+    visitor: &mut V,
+    item: &'a Item<impl WalkItemKind<Ctxt = ()>>,
+) -> V::Result {
+    walk_item_ctxt(visitor, item, ())
+}
+
+pub fn walk_assoc_item<'a, V: Visitor<'a>>(
+    visitor: &mut V,
+    item: &'a AssocItem,
+    ctxt: AssocCtxt,
+) -> V::Result {
+    walk_item_ctxt(visitor, item, ctxt)
+}
+
+fn walk_item_ctxt<'a, V: Visitor<'a>, K: WalkItemKind>(
     visitor: &mut V,
     item: &'a Item<K>,
     ctxt: K::Ctxt,
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index de9f5187be7..d7c531f3760 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -942,9 +942,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
             token::CloseDelim(Delimiter::Bracket) => "]".into(),
             token::OpenDelim(Delimiter::Brace) => "{".into(),
             token::CloseDelim(Delimiter::Brace) => "}".into(),
-            token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
-                "".into()
-            }
+            token::OpenDelim(Delimiter::Invisible(_))
+            | token::CloseDelim(Delimiter::Invisible(_)) => "".into(),
             token::Pound => "#".into(),
             token::Dollar => "$".into(),
             token::Question => "?".into(),
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 7adc7a8863e..452038bc328 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -641,6 +641,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
             | mir::StatementKind::Coverage(..)
             | mir::StatementKind::Intrinsic(..)
             | mir::StatementKind::ConstEvalCounter
+            | mir::StatementKind::BackwardIncompatibleDropHint { .. }
             | mir::StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 03f7b05d1e3..16a4f699177 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -652,6 +652,8 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
             | StatementKind::Coverage(..)
             // These do not actually affect borrowck
             | StatementKind::ConstEvalCounter
+            // This do not affect borrowck
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index d1b65943199..f646beeecf7 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -88,6 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
             | StatementKind::Nop
             | StatementKind::Retag { .. }
             | StatementKind::Deinit(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index c6b34d5bf1d..3a7ed711f68 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1252,6 +1252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             | StatementKind::Coverage(..)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
             StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index e7ee6b43e27..d46a1bd3d31 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -215,7 +215,7 @@ impl MutVisitor for CfgEval<'_> {
         foreign_item: P<ast::ForeignItem>,
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
         let foreign_item = configure!(self, foreign_item);
-        mut_visit::walk_flat_map_item(self, foreign_item)
+        mut_visit::walk_flat_map_foreign_item(self, foreign_item)
     }
 
     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index ba5d34359aa..b2048c534a4 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -1,6 +1,6 @@
 // Code that generates a test runner to run all the tests in a crate
 
-use std::{iter, mem};
+use std::mem;
 
 use rustc_ast as ast;
 use rustc_ast::entry::EntryPointType;
@@ -19,7 +19,7 @@ use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
 use rustc_span::symbol::{Ident, Symbol, sym};
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::spec::PanicStrategy;
-use smallvec::{SmallVec, smallvec};
+use smallvec::smallvec;
 use thin_vec::{ThinVec, thin_vec};
 use tracing::debug;
 
@@ -129,8 +129,9 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
         c.items.push(mk_main(&mut self.cx));
     }
 
-    fn flat_map_item(&mut self, mut i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
-        let item = &mut *i;
+    fn visit_item(&mut self, item: &mut P<ast::Item>) {
+        let item = &mut **item;
+
         if let Some(name) = get_test_name(&item) {
             debug!("this is a test item");
 
@@ -158,7 +159,6 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
             // But in those cases, we emit a lint to warn the user of these missing tests.
             walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
         }
-        smallvec![i]
     }
 }
 
@@ -198,40 +198,30 @@ struct EntryPointCleaner<'a> {
 }
 
 impl<'a> MutVisitor for EntryPointCleaner<'a> {
-    fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+    fn visit_item(&mut self, item: &mut P<ast::Item>) {
         self.depth += 1;
-        let item = walk_flat_map_item(self, i).expect_one("noop did something");
+        ast::mut_visit::walk_item(self, item);
         self.depth -= 1;
 
         // Remove any #[rustc_main] or #[start] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
-        let item = match entry_point_type(&item, self.depth == 0) {
+        match entry_point_type(&item, self.depth == 0) {
             EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
-                item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
-                    let allow_dead_code = attr::mk_attr_nested_word(
-                        &self.sess.psess.attr_id_generator,
-                        ast::AttrStyle::Outer,
-                        ast::Safety::Default,
-                        sym::allow,
-                        sym::dead_code,
-                        self.def_site,
-                    );
-                    let attrs = attrs
-                        .into_iter()
-                        .filter(|attr| {
-                            !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)
-                        })
-                        .chain(iter::once(allow_dead_code))
-                        .collect();
-
-                    ast::Item { id, ident, attrs, kind, vis, span, tokens }
-                })
+                let allow_dead_code = attr::mk_attr_nested_word(
+                    &self.sess.psess.attr_id_generator,
+                    ast::AttrStyle::Outer,
+                    ast::Safety::Default,
+                    sym::allow,
+                    sym::dead_code,
+                    self.def_site,
+                );
+                item.attrs
+                    .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start));
+                item.attrs.push(allow_dead_code);
             }
-            EntryPointType::None | EntryPointType::OtherMain => item,
+            EntryPointType::None | EntryPointType::OtherMain => {}
         };
-
-        smallvec![item]
     }
 }
 
@@ -292,7 +282,7 @@ fn generate_test_harness(
 /// Most of the Ident have the usual def-site hygiene for the AST pass. The
 /// exception is the `test_const`s. These have a syntax context that has two
 /// opaque marks: one from the expansion of `test` or `test_case`, and one
-/// generated  in `TestHarnessGenerator::flat_map_item`. When resolving this
+/// generated  in `TestHarnessGenerator::visit_item`. When resolving this
 /// identifier after failing to find a matching identifier in the root module
 /// we remove the outer mark, and try resolving at its def-site, which will
 /// then resolve to `test_const`.
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 77ee9773940..70b7d92ce15 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -924,6 +924,7 @@ fn codegen_stmt<'tcx>(
         | StatementKind::FakeRead(..)
         | StatementKind::Retag { .. }
         | StatementKind::PlaceMention(..)
+        | StatementKind::BackwardIncompatibleDropHint { .. }
         | StatementKind::AscribeUserType(..) => {}
 
         StatementKind::Coverage { .. } => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 5311547309c..abe6085b04f 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -583,6 +583,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         | StatementKind::PlaceMention(..)
                         | StatementKind::Coverage(_)
                         | StatementKind::ConstEvalCounter
+                        | StatementKind::BackwardIncompatibleDropHint { .. }
                         | StatementKind::Nop => {}
                     }
                 }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index fd1126e8528..5149e3a12f2 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -777,6 +777,16 @@ fn link_natively(
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let (linker_path, flavor) = linker_and_flavor(sess);
     let self_contained_components = self_contained_components(sess, crate_type);
+
+    // On AIX, we ship all libraries as .a big_af archive
+    // the expected format is lib<name>.a(libname.so) for the actual
+    // dynamic library. So we link to a temporary .so file to be archived
+    // at the final out_filename location
+    let should_archive = crate_type != CrateType::Executable && sess.target.is_like_aix;
+    let archive_member =
+        should_archive.then(|| tmpdir.join(out_filename.file_name().unwrap()).with_extension("so"));
+    let temp_filename = archive_member.as_deref().unwrap_or(out_filename);
+
     let mut cmd = linker_with_args(
         &linker_path,
         flavor,
@@ -784,7 +794,7 @@ fn link_natively(
         archive_builder_builder,
         crate_type,
         tmpdir,
-        out_filename,
+        temp_filename,
         codegen_results,
         self_contained_components,
     )?;
@@ -1158,6 +1168,12 @@ fn link_natively(
         }
     }
 
+    if should_archive {
+        let mut ab = archive_builder_builder.new_archive_builder(sess);
+        ab.add_file(temp_filename);
+        ab.build(out_filename);
+    }
+
     Ok(())
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 4f3664a503d..6ee599c9964 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1279,7 +1279,7 @@ impl<'a> WasmLd<'a> {
         let mut wasm_ld = WasmLd { cmd, sess };
         if sess.target_features.contains(&sym::atomics) {
             wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
-            if sess.target.os == "unknown" {
+            if sess.target.os == "unknown" || sess.target.os == "none" {
                 wasm_ld.link_args(&[
                     "--export=__wasm_init_tls",
                     "--export=__tls_size",
@@ -1403,7 +1403,7 @@ impl<'a> Linker for WasmLd<'a> {
         // symbols explicitly passed via the `--export` flags above and hides all
         // others. Various bits and pieces of wasm32-unknown-unknown tooling use
         // this, so be sure these symbols make their way out of the linker as well.
-        if self.sess.target.os == "unknown" {
+        if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
             self.link_args(&["--export=__heap_base", "--export=__data_end"]);
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index bdf7030f946..ba7b53321a8 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -5,6 +5,7 @@ use std::fs::File;
 use std::io::Write;
 use std::path::Path;
 
+use itertools::Itertools;
 use object::write::{self, StandardSegment, Symbol, SymbolSection};
 use object::{
     Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, ObjectSymbol,
@@ -21,6 +22,7 @@ use rustc_middle::bug;
 use rustc_session::Session;
 use rustc_span::sym;
 use rustc_target::spec::{RelocModel, Target, ef_avr_arch};
+use tracing::debug;
 
 use super::apple;
 
@@ -53,6 +55,7 @@ fn load_metadata_with(
 
 impl MetadataLoader for DefaultMetadataLoader {
     fn get_rlib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
+        debug!("getting rlib metadata for {}", path.display());
         load_metadata_with(path, |data| {
             let archive = object::read::archive::ArchiveFile::parse(&*data)
                 .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
@@ -77,8 +80,26 @@ impl MetadataLoader for DefaultMetadataLoader {
     }
 
     fn get_dylib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
+        debug!("getting dylib metadata for {}", path.display());
         if target.is_like_aix {
-            load_metadata_with(path, |data| get_metadata_xcoff(path, data))
+            load_metadata_with(path, |data| {
+                let archive = object::read::archive::ArchiveFile::parse(&*data).map_err(|e| {
+                    format!("failed to parse aix dylib '{}': {}", path.display(), e)
+                })?;
+
+                match archive.members().exactly_one() {
+                    Ok(lib) => {
+                        let lib = lib.map_err(|e| {
+                            format!("failed to parse aix dylib '{}': {}", path.display(), e)
+                        })?;
+                        let data = lib.data(data).map_err(|e| {
+                            format!("failed to parse aix dylib '{}': {}", path.display(), e)
+                        })?;
+                        get_metadata_xcoff(path, data)
+                    }
+                    Err(e) => Err(format!("failed to parse aix dylib '{}': {}", path.display(), e)),
+                }
+            })
         } else {
             load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
         }
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 1681ea1de5f..cd55a838a75 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -92,6 +92,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             | mir::StatementKind::AscribeUserType(..)
             | mir::StatementKind::ConstEvalCounter
             | mir::StatementKind::PlaceMention(..)
+            | mir::StatementKind::BackwardIncompatibleDropHint { .. }
             | mir::StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 8e96d365beb..1129b5caec5 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -609,6 +609,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
     }
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 64331eea75c..647d880e2bf 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -7,7 +7,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
 use rustc_middle::mir::{self, ConstAlloc, ConstValue};
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
@@ -30,7 +30,6 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
     cid: GlobalId<'tcx>,
     body: &'tcx mir::Body<'tcx>,
 ) -> InterpResult<'tcx, R> {
-    trace!(?ecx.typing_env);
     let tcx = *ecx.tcx;
     assert!(
         cid.promoted.is_some()
@@ -220,7 +219,7 @@ pub(super) fn op_to_const<'tcx>(
                 let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
                 debug_assert!(
                     matches!(
-                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env).kind(),
+                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(),
                         ty::Str | ty::Slice(..),
                     ),
                     "`ConstValue::Slice` is for slice-tailed types only, but got {}",
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index db82050c73c..b27e3606f38 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
 use rustc_middle::mir::AssertMessage;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::Span;
@@ -667,7 +667,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                 .is_some_and(|p| !p.immutable())
         {
             // That next check is expensive, that's why we have all the guards above.
-            let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env);
+            let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env());
             let place = ecx.ref_to_mplace(val)?;
             let new_place = if is_immutable {
                 place.map_provenance(CtfeProvenance::as_immutable)
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 42fdf32e91e..fe93a48c2f2 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -39,8 +39,8 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> {
     pub tcx: TyCtxtAt<'tcx>,
 
     /// The current context in case we're evaluating in a
-    /// polymorphic context. This always uses `ty::TypingMode::PostAnalysis`
-    pub typing_env: ty::TypingEnv<'tcx>,
+    /// polymorphic context. This always uses `ty::TypingMode::PostAnalysis`.
+    pub(super) typing_env: ty::TypingEnv<'tcx>,
 
     /// The virtual memory system.
     pub memory: Memory<'tcx, M>,
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 98aca37e73e..b61865be667 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -143,6 +143,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
             Nop => {}
+
+            // Only used for temporary lifetime lints
+            BackwardIncompatibleDropHint { .. } => {}
         }
 
         interp_ok(())
diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
index bafb16a8b5e..34895d3efe6 100644
--- a/compiler/rustc_data_structures/src/unord.rs
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -602,6 +602,11 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
             .into_iter()
             .map(|(_, v)| v)
     }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
 }
 
 impl<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V>
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index 31837e01764..05e11c4527f 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -23,3 +23,5 @@ driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc ver
 driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
 
 driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
+
+driver_impl_unstable_feature_usage = cannot dump feature usage metrics: {$error}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 8dd043be6ad..c270ce16726 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -15,6 +15,7 @@
 #![feature(panic_update_hook)]
 #![feature(result_flattening)]
 #![feature(rustdoc_internals)]
+#![feature(try_blocks)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
@@ -50,6 +51,7 @@ use rustc_interface::{Linker, Queries, interface, passes};
 use rustc_lint::unerased_lint_store;
 use rustc_metadata::creader::MetadataLoader;
 use rustc_metadata::locator;
+use rustc_middle::ty::TyCtxt;
 use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::config::{
     CG_OPTIONS, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, Z_OPTIONS,
@@ -102,7 +104,7 @@ mod signal_handler {
 
 use crate::session_diagnostics::{
     RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch,
-    RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead,
+    RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, UnstableFeatureUsage,
 };
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
@@ -430,6 +432,10 @@ fn run_compiler(
             // Make sure name resolution and macro expansion is run.
             queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering());
 
+            if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
+                queries.global_ctxt()?.enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir));
+            }
+
             if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
@@ -474,6 +480,23 @@ fn run_compiler(
     })
 }
 
+fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &PathBuf) {
+    let output_filenames = tcxt.output_filenames(());
+    let mut metrics_file_name = std::ffi::OsString::from("unstable_feature_usage_metrics-");
+    let mut metrics_path = output_filenames.with_directory_and_extension(metrics_dir, "json");
+    let metrics_file_stem =
+        metrics_path.file_name().expect("there should be a valid default output filename");
+    metrics_file_name.push(metrics_file_stem);
+    metrics_path.pop();
+    metrics_path.push(metrics_file_name);
+    if let Err(error) = tcxt.features().dump_feature_usage_metrics(metrics_path) {
+        // FIXME(yaahc): once metrics can be enabled by default we will want "failure to emit
+        // default metrics" to only produce a warning when metrics are enabled by default and emit
+        // an error only when the user manually enables metrics
+        tcxt.dcx().emit_err(UnstableFeatureUsage { error });
+    }
+}
+
 // Extract output directory and file from matches.
 fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileName>) {
     let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
@@ -564,71 +587,63 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col
     }
 }
 
-/// If color is always or auto, print formatted & colorized markdown. If color is never or
-/// if formatted printing fails, print the raw text.
+/// If `color` is `always` or `auto`, try to print pretty (formatted & colorized) markdown. If
+/// that fails or `color` is `never`, print the raw markdown.
 ///
-/// Prefers a pager, falls back standard print
+/// Uses a pager if possible, falls back to stdout.
 fn show_md_content_with_pager(content: &str, color: ColorConfig) {
-    let mut fallback_to_println = false;
     let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
         if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
     });
 
     let mut cmd = Command::new(&pager_name);
-    // FIXME: find if other pagers accept color options
-    let mut print_formatted = if pager_name == "less" {
-        cmd.arg("-R");
-        true
-    } else {
-        ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name)
-    };
-
-    if color == ColorConfig::Never {
-        print_formatted = false;
-    } else if color == ColorConfig::Always {
-        print_formatted = true;
-    }
-
-    let mdstream = markdown::MdStream::parse_str(content);
-    let bufwtr = markdown::create_stdout_bufwtr();
-    let mut mdbuf = bufwtr.buffer();
-    if mdstream.write_termcolor_buf(&mut mdbuf).is_err() {
-        print_formatted = false;
+    if pager_name == "less" {
+        cmd.arg("-R"); // allows color escape sequences
     }
 
-    if let Ok(mut pager) = cmd.stdin(Stdio::piped()).spawn() {
-        if let Some(pipe) = pager.stdin.as_mut() {
-            let res = if print_formatted {
-                pipe.write_all(mdbuf.as_slice())
-            } else {
-                pipe.write_all(content.as_bytes())
-            };
-
-            if res.is_err() {
-                fallback_to_println = true;
-            }
+    let pretty_on_pager = match color {
+        ColorConfig::Auto => {
+            // Add other pagers that accept color escape sequences here.
+            ["less", "bat", "batcat", "delta"].iter().any(|v| *v == pager_name)
         }
+        ColorConfig::Always => true,
+        ColorConfig::Never => false,
+    };
 
-        if pager.wait().is_err() {
-            fallback_to_println = true;
-        }
-    } else {
-        fallback_to_println = true;
-    }
+    // Try to prettify the raw markdown text. The result can be used by the pager or on stdout.
+    let pretty_data = {
+        let mdstream = markdown::MdStream::parse_str(content);
+        let bufwtr = markdown::create_stdout_bufwtr();
+        let mut mdbuf = bufwtr.buffer();
+        if mdstream.write_termcolor_buf(&mut mdbuf).is_ok() { Some((bufwtr, mdbuf)) } else { None }
+    };
+
+    // Try to print via the pager, pretty output if possible.
+    let pager_res: Option<()> = try {
+        let mut pager = cmd.stdin(Stdio::piped()).spawn().ok()?;
 
-    // If pager fails for whatever reason, we should still print the content
-    // to standard output
-    if fallback_to_println {
-        let fmt_success = match color {
-            ColorConfig::Auto => io::stdout().is_terminal() && bufwtr.print(&mdbuf).is_ok(),
-            ColorConfig::Always => bufwtr.print(&mdbuf).is_ok(),
-            ColorConfig::Never => false,
+        let pager_stdin = pager.stdin.as_mut()?;
+        if pretty_on_pager && let Some((_, mdbuf)) = &pretty_data {
+            pager_stdin.write_all(mdbuf.as_slice()).ok()?;
+        } else {
+            pager_stdin.write_all(content.as_bytes()).ok()?;
         };
 
-        if !fmt_success {
-            safe_print!("{content}");
-        }
+        pager.wait().ok()?;
+    };
+    if pager_res.is_some() {
+        return;
+    }
+
+    // The pager failed. Try to print pretty output to stdout.
+    if let Some((bufwtr, mdbuf)) = &pretty_data
+        && bufwtr.print(&mdbuf).is_ok()
+    {
+        return;
     }
+
+    // Everything failed. Print the raw markdown text.
+    safe_print!("{content}");
 }
 
 fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs
index 449878f28c4..e06c56539d1 100644
--- a/compiler/rustc_driver_impl/src/session_diagnostics.rs
+++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs
@@ -1,3 +1,5 @@
+use std::error::Error;
+
 use rustc_macros::{Diagnostic, Subdiagnostic};
 
 #[derive(Diagnostic)]
@@ -93,3 +95,9 @@ pub(crate) struct IceFlags {
 #[derive(Diagnostic)]
 #[diag(driver_impl_ice_exclude_cargo_defaults)]
 pub(crate) struct IceExcludeCargoDefaults;
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_unstable_feature_usage)]
+pub(crate) struct UnstableFeatureUsage {
+    pub error: Box<dyn Error>,
+}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 91786462b40..19c2d466f7c 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1382,7 +1382,7 @@ impl InvocationCollectorNode for P<ast::ForeignItem> {
         fragment.make_foreign_items()
     }
     fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        walk_flat_map_item(visitor, self)
+        walk_flat_map_foreign_item(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ForeignItemKind::MacCall(..))
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index ffcce1e52f6..77b8d228922 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -1,6 +1,6 @@
 use std::borrow::Cow;
 
-use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
 use rustc_macros::Subdiagnostic;
@@ -68,7 +68,9 @@ pub(super) fn failed_to_match_macro(
 
     if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
         && (matches!(expected_token.kind, TokenKind::Interpolated(_))
-            || matches!(token.kind, TokenKind::Interpolated(_)))
+            || matches!(token.kind, TokenKind::Interpolated(_))
+            || matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
+            || matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
     {
         err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
         err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index fcc90c3ce0d..a373c753cc1 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -693,7 +693,7 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
                     && let mbe::TokenTree::Token(bang) = bang
                     && let TokenKind::Not = bang.kind
                     && let mbe::TokenTree::Delimited(.., del) = args
-                    && del.delim != Delimiter::Invisible
+                    && !del.delim.skip()
                 {
                     true
                 } else {
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 1345f06d5ac..36094707fac 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -165,11 +165,12 @@ fn parse_tree<'a>(
             // during parsing.
             let mut next = outer_trees.next();
             let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>;
-            if let Some(tokenstream::TokenTree::Delimited(.., Delimiter::Invisible, tts)) = next {
-                trees = Box::new(tts.trees());
-                next = trees.next();
-            } else {
-                trees = Box::new(outer_trees);
+            match next {
+                Some(tokenstream::TokenTree::Delimited(.., delim, tts)) if delim.skip() => {
+                    trees = Box::new(tts.trees());
+                    next = trees.next();
+                }
+                _ => trees = Box::new(outer_trees),
             }
 
             match next {
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 90206b19bd5..bae16a18bcb 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -296,7 +296,7 @@ impl MutVisitor for PlaceholderExpander {
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
         match item.kind {
             ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(),
-            _ => walk_flat_map_item(self, item),
+            _ => walk_flat_map_foreign_item(self, item),
         }
     }
 
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 0dc35618ff8..263df235b3e 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -38,7 +38,7 @@ impl FromInternal<token::Delimiter> for Delimiter {
             token::Delimiter::Parenthesis => Delimiter::Parenthesis,
             token::Delimiter::Brace => Delimiter::Brace,
             token::Delimiter::Bracket => Delimiter::Bracket,
-            token::Delimiter::Invisible => Delimiter::None,
+            token::Delimiter::Invisible(_) => Delimiter::None,
         }
     }
 }
@@ -49,7 +49,7 @@ impl ToInternal<token::Delimiter> for Delimiter {
             Delimiter::Parenthesis => token::Delimiter::Parenthesis,
             Delimiter::Brace => token::Delimiter::Brace,
             Delimiter::Bracket => token::Delimiter::Bracket,
-            Delimiter::None => token::Delimiter::Invisible,
+            Delimiter::None => token::Delimiter::Invisible(token::InvisibleOrigin::ProcMacro),
         }
     }
 }
diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml
index 9df320e1279..77de7fabd4f 100644
--- a/compiler/rustc_feature/Cargo.toml
+++ b/compiler/rustc_feature/Cargo.toml
@@ -7,4 +7,6 @@ edition = "2021"
 # tidy-alphabetical-start
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_span = { path = "../rustc_span" }
+serde = { version = "1.0.125", features = [ "derive" ] }
+serde_json = "1.0.59"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 2acebebb419..e3dc73c1401 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -1,5 +1,7 @@
 //! List of the unstable feature gates.
 
+use std::path::PathBuf;
+
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
@@ -651,6 +653,54 @@ declare_features! (
     // -------------------------------------------------------------------------
 );
 
+impl Features {
+    pub fn dump_feature_usage_metrics(
+        &self,
+        metrics_path: PathBuf,
+    ) -> Result<(), Box<dyn std::error::Error>> {
+        #[derive(serde::Serialize)]
+        struct LibFeature {
+            symbol: String,
+        }
+
+        #[derive(serde::Serialize)]
+        struct LangFeature {
+            symbol: String,
+            since: Option<String>,
+        }
+
+        #[derive(serde::Serialize)]
+        struct FeatureUsage {
+            lib_features: Vec<LibFeature>,
+            lang_features: Vec<LangFeature>,
+        }
+
+        let metrics_file = std::fs::File::create(metrics_path)?;
+        let metrics_file = std::io::BufWriter::new(metrics_file);
+
+        let lib_features = self
+            .enabled_lib_features
+            .iter()
+            .map(|EnabledLibFeature { gate_name, .. }| LibFeature { symbol: gate_name.to_string() })
+            .collect();
+
+        let lang_features = self
+            .enabled_lang_features
+            .iter()
+            .map(|EnabledLangFeature { gate_name, stable_since, .. }| LangFeature {
+                symbol: gate_name.to_string(),
+                since: stable_since.map(|since| since.to_string()),
+            })
+            .collect();
+
+        let feature_usage = FeatureUsage { lib_features, lang_features };
+
+        serde_json::to_writer(metrics_file, &feature_usage)?;
+
+        Ok(())
+    }
+}
+
 /// Some features are not allowed to be used together at the same time, if
 /// the two are present, produce an error.
 ///
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index aa9d303cacb..cf3f3003bf5 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -339,6 +339,8 @@ fn check_opaque_meets_bounds<'tcx>(
 
     let misc_cause = ObligationCause::misc(span, def_id);
     // FIXME: We should just register the item bounds here, rather than equating.
+    // FIXME(const_trait_impl): When we do that, please make sure to also register
+    // the `~const` bounds.
     match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
         Ok(()) => {}
         Err(ty_err) => {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 8a051e34f82..bd0b0ceb92d 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -2083,7 +2083,7 @@ pub(super) fn check_type_bounds<'tcx>(
     // Only in a const implementation do we need to check that the `~const` item bounds hold.
     if tcx.is_conditionally_const(impl_ty_def_id) {
         obligations.extend(
-            tcx.implied_const_bounds(trait_ty.def_id)
+            tcx.explicit_implied_const_bounds(trait_ty.def_id)
                 .iter_instantiated_copied(tcx, rebased_args)
                 .map(|(c, span)| {
                     traits::Obligation::new(
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 679f6ccb816..b9cb48cafdc 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -17,6 +17,7 @@ use rustc_index::Idx;
 use rustc_middle::bug;
 use rustc_middle::middle::region::*;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::lint;
 use rustc_span::source_map;
 use tracing::debug;
 
@@ -167,8 +168,23 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
             }
         }
         if let Some(tail_expr) = blk.expr {
-            if blk.span.edition().at_least_rust_2024() {
-                visitor.terminating_scopes.insert(tail_expr.hir_id.local_id);
+            let local_id = tail_expr.hir_id.local_id;
+            let edition = blk.span.edition();
+            if edition.at_least_rust_2024() {
+                visitor.terminating_scopes.insert(local_id);
+            } else if !visitor
+                .tcx
+                .lints_that_dont_need_to_run(())
+                .contains(&lint::LintId::of(lint::builtin::TAIL_EXPR_DROP_ORDER))
+            {
+                // If this temporary scope will be changing once the codebase adopts Rust 2024,
+                // and we are linting about possible semantic changes that would result,
+                // then record this node-id in the field `backwards_incompatible_scope`
+                // for future reference.
+                visitor
+                    .scope_tree
+                    .backwards_incompatible_scope
+                    .insert(local_id, Scope { id: local_id, data: ScopeData::Node });
             }
             visitor.visit_expr(tail_expr);
         }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index c2ad61820a7..3b49bc41ffe 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     let lang_items = tcx.lang_items();
     let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
-    let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
-    res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
-    res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| {
+    checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
+    checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
+    checker.check(lang_items.const_param_ty_trait(), |checker| {
         visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
-    }));
-    res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
+    })?;
+    checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
         visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
-    }));
-
-    res = res.and(
-        checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
-    );
-    res.and(
-        checker
-            .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
-    )
+    })?;
+    checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
+    checker
+        .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
+    checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
+    Ok(())
 }
 
 struct Checker<'tcx> {
@@ -663,3 +660,63 @@ fn infringing_fields_error<'tcx>(
 
     err.emit()
 }
+
+fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
+    let tcx = checker.tcx;
+    let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
+    let impl_span = tcx.def_span(checker.impl_def_id);
+    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
+
+    // If an ADT is repr(transparent)...
+    if let ty::Adt(def, args) = *self_ty.kind()
+        && def.repr().transparent()
+    {
+        // FIXME(compiler-errors): This should and could be deduplicated into a query.
+        // Find the nontrivial field.
+        let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did());
+        let nontrivial_field = def.all_fields().find(|field_def| {
+            let field_ty = tcx.type_of(field_def.did).instantiate_identity();
+            !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
+                .is_ok_and(|layout| layout.layout.is_1zst())
+        });
+
+        if let Some(nontrivial_field) = nontrivial_field {
+            // Check that the nontrivial field implements `PointerLike`.
+            let nontrivial_field = nontrivial_field.ty(tcx, args);
+            let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+            let ocx = ObligationCtxt::new(&infcx);
+            ocx.register_bound(
+                ObligationCause::misc(impl_span, checker.impl_def_id),
+                param_env,
+                nontrivial_field,
+                tcx.lang_items().pointer_like().unwrap(),
+            );
+            // FIXME(dyn-star): We should regionck this implementation.
+            if ocx.select_all_or_error().is_empty() {
+                return Ok(());
+            }
+        }
+    }
+
+    let is_permitted_primitive = match *self_ty.kind() {
+        ty::Adt(def, _) => def.is_box(),
+        ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
+        _ => false,
+    };
+
+    if is_permitted_primitive
+        && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
+        && layout.layout.is_pointer_like(&tcx.data_layout)
+    {
+        return Ok(());
+    }
+
+    Err(tcx
+        .dcx()
+        .struct_span_err(
+            impl_span,
+            "implementation must be applied to type that has the same ABI as a pointer, \
+            or is `repr(transparent)` and whose field is `PointerLike`",
+        )
+        .emit())
+}
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 1a925597c6c..73b73afb0a5 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -78,7 +78,7 @@ pub fn provide(providers: &mut Providers) {
             predicates_of::explicit_supertraits_containing_assoc_item,
         trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
         const_conditions: predicates_of::const_conditions,
-        implied_const_bounds: predicates_of::implied_const_bounds,
+        explicit_implied_const_bounds: predicates_of::explicit_implied_const_bounds,
         type_param_predicates: predicates_of::type_param_predicates,
         trait_def,
         adt_def,
@@ -340,6 +340,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
         self.tcx.ensure().explicit_item_super_predicates(def_id);
         self.tcx.ensure().item_bounds(def_id);
         self.tcx.ensure().item_super_predicates(def_id);
+        if self.tcx.is_conditionally_const(def_id) {
+            self.tcx.ensure().explicit_implied_const_bounds(def_id);
+            self.tcx.ensure().const_conditions(def_id);
+        }
         intravisit::walk_opaque_ty(self, opaque);
     }
 
@@ -682,6 +686,10 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 tcx.ensure().generics_of(item.owner_id);
                 tcx.ensure().type_of(item.owner_id);
                 tcx.ensure().predicates_of(item.owner_id);
+                if tcx.is_conditionally_const(def_id) {
+                    tcx.ensure().explicit_implied_const_bounds(def_id);
+                    tcx.ensure().const_conditions(def_id);
+                }
                 match item.kind {
                     hir::ForeignItemKind::Fn(..) => {
                         tcx.ensure().codegen_fn_attrs(item.owner_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 0f37d61beb0..b5dee5bd021 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -959,6 +959,12 @@ pub(super) fn const_conditions<'tcx>(
             hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false),
             _ => bug!("const_conditions called on wrong item: {def_id:?}"),
         },
+        Node::OpaqueTy(opaque) => match opaque.origin {
+            hir::OpaqueTyOrigin::FnReturn { parent, .. } => return tcx.const_conditions(parent),
+            hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => {
+                unreachable!()
+            }
+        },
         // N.B. Tuple ctors are unconditionally constant.
         Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
         _ => bug!("const_conditions called on wrong item: {def_id:?}"),
@@ -1018,7 +1024,7 @@ pub(super) fn const_conditions<'tcx>(
     }
 }
 
-pub(super) fn implied_const_bounds<'tcx>(
+pub(super) fn explicit_implied_const_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
 ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
@@ -1034,10 +1040,11 @@ pub(super) fn implied_const_bounds<'tcx>(
                 PredicateFilter::SelfConstIfConst,
             )
         }
-        Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => {
+        Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
+        | Node::OpaqueTy(_) => {
             explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
         }
-        _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"),
+        _ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"),
     };
 
     bounds.map_bound(|bounds| {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index dd0f250a8e2..4e5a8271e9e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1106,7 +1106,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     .collect::<String>()
             ),
             [(only, _)] => only.to_string(),
-            [] => "this type".to_string(),
+            [] => bug!("expected one segment to deny"),
         };
 
         let arg_spans: Vec<Span> = segments
@@ -1136,7 +1136,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 "s",
             ),
             [only] => (only.to_string(), ""),
-            [] => unreachable!("expected at least one generic to prohibit"),
+            [] => bug!("expected at least one generic to prohibit"),
         };
         let last_span = *arg_spans.last().unwrap();
         let span: MultiSpan = arg_spans.into();
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 34effd199f1..246643d8074 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -70,6 +70,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
@@ -210,13 +211,7 @@ fn get_impl_args(
         impl1_def_id.to_def_id(),
         impl1_args,
         impl2_node,
-        |_, span| {
-            traits::ObligationCause::new(
-                impl1_span,
-                impl1_def_id,
-                traits::ObligationCauseCode::WhereClause(impl2_node.def_id(), span),
-            )
-        },
+        &ObligationCause::misc(impl1_span, impl1_def_id),
     );
 
     let errors = ocx.select_all_or_error();
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 8772599e316..cff2aa68993 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -31,6 +31,7 @@ use rustc_span::symbol::{Ident, kw, sym};
 use rustc_span::{
     DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span, Symbol, edit_distance,
 };
+use rustc_trait_selection::error_reporting::traits::DefIdOrName;
 use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -45,50 +46,6 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
 use crate::{Expectation, FnCtxt};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
-        let tcx = self.tcx;
-        match ty.kind() {
-            // Not all of these (e.g., unsafe fns) implement `FnOnce`,
-            // so we look for these beforehand.
-            // FIXME(async_closures): These don't impl `FnOnce` by default.
-            ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(..) => true,
-            // If it's not a simple function, look for things which implement `FnOnce`.
-            _ => {
-                let Some(fn_once) = tcx.lang_items().fn_once_trait() else {
-                    return false;
-                };
-
-                // This conditional prevents us from asking to call errors and unresolved types.
-                // It might seem that we can use `predicate_must_hold_modulo_regions`,
-                // but since a Dummy binder is used to fill in the FnOnce trait's arguments,
-                // type resolution always gives a "maybe" here.
-                if self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
-                    info!("check deref {:?} error", ty);
-                    matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
-                }) {
-                    return false;
-                }
-
-                self.autoderef(span, ty).silence_errors().any(|(ty, _)| {
-                    info!("check deref {:?} impl FnOnce", ty);
-                    self.probe(|_| {
-                        let trait_ref =
-                            ty::TraitRef::new(tcx, fn_once, [ty, self.next_ty_var(span)]);
-                        let poly_trait_ref = ty::Binder::dummy(trait_ref);
-                        let obligation = Obligation::misc(
-                            tcx,
-                            span,
-                            self.body_id,
-                            self.param_env,
-                            poly_trait_ref,
-                        );
-                        self.predicate_may_hold(&obligation)
-                    })
-                })
-            }
-        }
-    }
-
     fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
         self.autoderef(span, ty)
             .silence_errors()
@@ -2367,12 +2324,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let is_accessible = field.vis.is_accessible_from(scope, tcx);
 
             if is_accessible {
-                if self.is_fn_ty(field_ty, span) {
+                if let Some((what, _, _)) = self.extract_callable_info(field_ty) {
+                    let what = match what {
+                        DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),
+                        DefIdOrName::Name(what) => what,
+                    };
                     let expr_span = expr.span.to(item_name.span);
                     err.multipart_suggestion(
                         format!(
-                            "to call the function stored in `{item_name}`, \
-                                         surround the field access with parentheses",
+                            "to call the {what} stored in `{item_name}`, \
+                            surround the field access with parentheses",
                         ),
                         vec![
                             (expr_span.shrink_to_lo(), '('.to_string()),
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index c2b9cae680b..a9239489222 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -460,6 +460,10 @@ impl<T: Idx> ChunkedBitSet<T> {
         self.chunks.iter().map(|chunk| chunk.count()).sum()
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.chunks.iter().all(|chunk| matches!(chunk, Chunk::Zeros(..) | Chunk::Ones(0)))
+    }
+
     /// Returns `true` if `self` contains `elem`.
     #[inline]
     pub fn contains(&self, elem: T) -> bool {
@@ -668,12 +672,140 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
         changed
     }
 
-    fn subtract(&mut self, _other: &ChunkedBitSet<T>) -> bool {
-        unimplemented!("implement if/when necessary");
+    fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        debug_assert_eq!(self.chunks.len(), other.chunks.len());
+
+        let mut changed = false;
+        for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
+            match (&mut self_chunk, &other_chunk) {
+                (Zeros(..), _) | (_, Zeros(..)) => {}
+                (
+                    Ones(self_chunk_domain_size) | Mixed(self_chunk_domain_size, _, _),
+                    Ones(other_chunk_domain_size),
+                ) => {
+                    debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size);
+                    changed = true;
+                    *self_chunk = Zeros(*self_chunk_domain_size);
+                }
+                (
+                    Ones(self_chunk_domain_size),
+                    Mixed(other_chunk_domain_size, other_chunk_count, other_chunk_words),
+                ) => {
+                    debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size);
+                    changed = true;
+                    let num_words = num_words(*self_chunk_domain_size as usize);
+                    debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS);
+                    let mut tail_mask =
+                        1 << (*other_chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1;
+                    let mut self_chunk_words = **other_chunk_words;
+                    for word in self_chunk_words[0..num_words].iter_mut().rev() {
+                        *word = !*word & tail_mask;
+                        tail_mask = u64::MAX;
+                    }
+                    let self_chunk_count = *self_chunk_domain_size - *other_chunk_count;
+                    debug_assert_eq!(
+                        self_chunk_count,
+                        self_chunk_words[0..num_words]
+                            .iter()
+                            .map(|w| w.count_ones() as ChunkSize)
+                            .sum()
+                    );
+                    *self_chunk =
+                        Mixed(*self_chunk_domain_size, self_chunk_count, Rc::new(self_chunk_words));
+                }
+                (
+                    Mixed(
+                        self_chunk_domain_size,
+                        ref mut self_chunk_count,
+                        ref mut self_chunk_words,
+                    ),
+                    Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words),
+                ) => {
+                    // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation
+                    let op = |a: u64, b: u64| a & !b;
+                    let num_words = num_words(*self_chunk_domain_size as usize);
+                    if bitwise_changes(
+                        &self_chunk_words[0..num_words],
+                        &other_chunk_words[0..num_words],
+                        op,
+                    ) {
+                        let self_chunk_words = Rc::make_mut(self_chunk_words);
+                        let has_changed = bitwise(
+                            &mut self_chunk_words[0..num_words],
+                            &other_chunk_words[0..num_words],
+                            op,
+                        );
+                        debug_assert!(has_changed);
+                        *self_chunk_count = self_chunk_words[0..num_words]
+                            .iter()
+                            .map(|w| w.count_ones() as ChunkSize)
+                            .sum();
+                        if *self_chunk_count == 0 {
+                            *self_chunk = Zeros(*self_chunk_domain_size);
+                        }
+                        changed = true;
+                    }
+                }
+            }
+        }
+        changed
     }
 
-    fn intersect(&mut self, _other: &ChunkedBitSet<T>) -> bool {
-        unimplemented!("implement if/when necessary");
+    fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
+        assert_eq!(self.domain_size, other.domain_size);
+        debug_assert_eq!(self.chunks.len(), other.chunks.len());
+
+        let mut changed = false;
+        for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) {
+            match (&mut self_chunk, &other_chunk) {
+                (Zeros(..), _) | (_, Ones(..)) => {}
+                (
+                    Ones(self_chunk_domain_size),
+                    Zeros(other_chunk_domain_size) | Mixed(other_chunk_domain_size, ..),
+                )
+                | (Mixed(self_chunk_domain_size, ..), Zeros(other_chunk_domain_size)) => {
+                    debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size);
+                    changed = true;
+                    *self_chunk = other_chunk.clone();
+                }
+                (
+                    Mixed(
+                        self_chunk_domain_size,
+                        ref mut self_chunk_count,
+                        ref mut self_chunk_words,
+                    ),
+                    Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words),
+                ) => {
+                    // See [`<Self as BitRelations<ChunkedBitSet<T>>>::union`] for the explanation
+                    let op = |a, b| a & b;
+                    let num_words = num_words(*self_chunk_domain_size as usize);
+                    if bitwise_changes(
+                        &self_chunk_words[0..num_words],
+                        &other_chunk_words[0..num_words],
+                        op,
+                    ) {
+                        let self_chunk_words = Rc::make_mut(self_chunk_words);
+                        let has_changed = bitwise(
+                            &mut self_chunk_words[0..num_words],
+                            &other_chunk_words[0..num_words],
+                            op,
+                        );
+                        debug_assert!(has_changed);
+                        *self_chunk_count = self_chunk_words[0..num_words]
+                            .iter()
+                            .map(|w| w.count_ones() as ChunkSize)
+                            .sum();
+                        if *self_chunk_count == 0 {
+                            *self_chunk = Zeros(*self_chunk_domain_size);
+                        }
+                        changed = true;
+                    }
+                }
+            }
+        }
+
+        changed
     }
 }
 
diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs
index 1ac2c44e9dc..67ec7761133 100644
--- a/compiler/rustc_index_macros/src/newtype.rs
+++ b/compiler/rustc_index_macros/src/newtype.rs
@@ -122,7 +122,7 @@ impl Parse for Newtype {
                 #gate_rustc_only
                 impl ::std::iter::Step for #name {
                     #[inline]
-                    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
                         <usize as ::std::iter::Step>::steps_between(
                             &Self::index(*start),
                             &Self::index(*end),
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index d65ed72a8e8..0aff4620314 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -574,9 +574,8 @@ impl<'tcx> InferCtxt<'tcx> {
         // unexpected region errors.
         goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into())));
 
-        let item_bounds = tcx.explicit_item_bounds(def_id);
-        for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
-            let predicate = predicate.fold_with(&mut BottomUpFolder {
+        let replace_opaques_in = |clause: ty::Clause<'tcx>, goals: &mut Vec<_>| {
+            clause.fold_with(&mut BottomUpFolder {
                 tcx,
                 ty_op: |ty| match *ty.kind() {
                     // We can't normalize associated types from `rustc_infer`,
@@ -612,11 +611,31 @@ impl<'tcx> InferCtxt<'tcx> {
                 },
                 lt_op: |lt| lt,
                 ct_op: |ct| ct,
-            });
+            })
+        };
+
+        let item_bounds = tcx.explicit_item_bounds(def_id);
+        for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
+            let predicate = replace_opaques_in(predicate, goals);
 
             // Require that the predicate holds for the concrete type.
             debug!(?predicate);
             goals.push(Goal::new(self.tcx, param_env, predicate));
         }
+
+        // If this opaque is being defined and it's conditionally const,
+        if self.tcx.is_conditionally_const(def_id) {
+            let item_bounds = tcx.explicit_implied_const_bounds(def_id);
+            for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
+                let predicate = replace_opaques_in(
+                    predicate.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe),
+                    goals,
+                );
+
+                // Require that the predicate holds for the concrete type.
+                debug!(?predicate);
+                goals.push(Goal::new(self.tcx, param_env, predicate));
+            }
+        }
     }
 }
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 6e35d89b488..69fd7f2d8b2 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -772,9 +772,6 @@ lint_suspicious_double_ref_clone =
 lint_suspicious_double_ref_deref =
     using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
 
-lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-    .label = these values have significant drop implementation and will observe changes in drop order under Edition 2024
-
 lint_trailing_semi_macro = trailing semicolon in macro used in expression position
     .note1 = macro invocations at the end of a block are treated as expressions
     .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index ef9b3dbd13b..4f3184f1d7c 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -230,15 +230,16 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
     }
 
     fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
-        self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt {
-            ast_visit::AssocCtxt::Trait => {
-                lint_callback!(cx, check_trait_item, item);
-                ast_visit::walk_assoc_item(cx, item, ctxt);
-            }
-            ast_visit::AssocCtxt::Impl => {
-                lint_callback!(cx, check_impl_item, item);
-                ast_visit::walk_assoc_item(cx, item, ctxt);
+        self.with_lint_attrs(item.id, &item.attrs, |cx| {
+            match ctxt {
+                ast_visit::AssocCtxt::Trait => {
+                    lint_callback!(cx, check_trait_item, item);
+                }
+                ast_visit::AssocCtxt::Impl => {
+                    lint_callback!(cx, check_impl_item, item);
+                }
             }
+            ast_visit::walk_assoc_item(cx, item, ctxt);
         });
     }
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 86112277504..4cf5c7b4ff9 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -75,7 +75,6 @@ mod redundant_semicolon;
 mod reference_casting;
 mod shadowed_into_iter;
 mod static_mut_refs;
-mod tail_expr_drop_order;
 mod traits;
 mod types;
 mod unit_bindings;
@@ -116,7 +115,6 @@ use rustc_middle::ty::TyCtxt;
 use shadowed_into_iter::ShadowedIntoIter;
 pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
 use static_mut_refs::*;
-use tail_expr_drop_order::TailExprDropOrder;
 use traits::*;
 use types::*;
 use unit_bindings::*;
@@ -240,7 +238,6 @@ late_lint_methods!(
             AsyncFnInTrait: AsyncFnInTrait,
             NonLocalDefinitions: NonLocalDefinitions::default(),
             ImplTraitOvercaptures: ImplTraitOvercaptures,
-            TailExprDropOrder: TailExprDropOrder,
             IfLetRescope: IfLetRescope::default(),
             StaticMutRefs: StaticMutRefs,
             UnqualifiedLocalImports: UnqualifiedLocalImports,
diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs
deleted file mode 100644
index 19763ce1ec5..00000000000
--- a/compiler/rustc_lint/src/tail_expr_drop_order.rs
+++ /dev/null
@@ -1,308 +0,0 @@
-use std::mem::swap;
-
-use rustc_ast::UnOp;
-use rustc_hir::def::Res;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, Block, Expr, ExprKind, LetStmt, Pat, PatKind, QPath, StmtKind};
-use rustc_macros::LintDiagnostic;
-use rustc_middle::ty;
-use rustc_session::lint::FutureIncompatibilityReason;
-use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::Span;
-use rustc_span::edition::Edition;
-
-use crate::{LateContext, LateLintPass};
-
-declare_lint! {
-    /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
-    /// that runs a custom `Drop` destructor.
-    /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior.
-    /// This lint detects those cases and provides you information on those values and their custom destructor implementations.
-    /// Your discretion on this information is required.
-    ///
-    /// ### Example
-    /// ```rust,edition2021
-    /// #![warn(tail_expr_drop_order)]
-    /// struct Droppy(i32);
-    /// impl Droppy {
-    ///     fn get(&self) -> i32 {
-    ///         self.0
-    ///     }
-    /// }
-    /// impl Drop for Droppy {
-    ///     fn drop(&mut self) {
-    ///         // This is a custom destructor and it induces side-effects that is observable
-    ///         // especially when the drop order at a tail expression changes.
-    ///         println!("loud drop {}", self.0);
-    ///     }
-    /// }
-    /// fn edition_2021() -> i32 {
-    ///     let another_droppy = Droppy(0);
-    ///     Droppy(1).get()
-    /// }
-    /// fn main() {
-    ///     edition_2021();
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// In tail expression of blocks or function bodies,
-    /// values of type with significant `Drop` implementation has an ill-specified drop order
-    /// before Edition 2024 so that they are dropped only after dropping local variables.
-    /// Edition 2024 introduces a new rule with drop orders for them,
-    /// so that they are dropped first before dropping local variables.
-    ///
-    /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary
-    /// implementation of the `Drop` trait on the type, with exceptions including `Vec`,
-    /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise
-    /// so long that the generic types have no significant destructor recursively.
-    /// In other words, a type has a significant drop destructor when it has a `Drop` implementation
-    /// or its destructor invokes a significant destructor on a type.
-    /// Since we cannot completely reason about the change by just inspecting the existence of
-    /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default.
-    ///
-    /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy`
-    /// does in Edition 2024.
-    /// No fix will be proposed by this lint.
-    /// However, the most probable fix is to hoist `Droppy` into its own local variable binding.
-    /// ```rust
-    /// struct Droppy(i32);
-    /// impl Droppy {
-    ///     fn get(&self) -> i32 {
-    ///         self.0
-    ///     }
-    /// }
-    /// fn edition_2024() -> i32 {
-    ///     let value = Droppy(0);
-    ///     let another_droppy = Droppy(1);
-    ///     value.get()
-    /// }
-    /// ```
-    pub TAIL_EXPR_DROP_ORDER,
-    Allow,
-    "Detect and warn on significant change in drop order in tail expression location",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
-        reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>",
-    };
-}
-
-declare_lint_pass!(TailExprDropOrder => [TAIL_EXPR_DROP_ORDER]);
-
-impl TailExprDropOrder {
-    fn check_fn_or_closure<'tcx>(
-        cx: &LateContext<'tcx>,
-        fn_kind: hir::intravisit::FnKind<'tcx>,
-        body: &'tcx hir::Body<'tcx>,
-        def_id: rustc_span::def_id::LocalDefId,
-    ) {
-        let mut locals = vec![];
-        if matches!(fn_kind, hir::intravisit::FnKind::Closure) {
-            for &capture in cx.tcx.closure_captures(def_id) {
-                if matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue)
-                    && capture.place.ty().has_significant_drop(cx.tcx, cx.typing_env())
-                {
-                    locals.push(capture.var_ident.span);
-                }
-            }
-        }
-        for param in body.params {
-            if cx
-                .typeck_results()
-                .node_type(param.hir_id)
-                .has_significant_drop(cx.tcx, cx.typing_env())
-            {
-                locals.push(param.span);
-            }
-        }
-        if let hir::ExprKind::Block(block, _) = body.value.kind {
-            LintVisitor { cx, locals }.check_block_inner(block);
-        } else {
-            LintTailExpr { cx, locals: &locals, is_root_tail_expr: true }.visit_expr(body.value);
-        }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        fn_kind: hir::intravisit::FnKind<'tcx>,
-        _: &'tcx hir::FnDecl<'tcx>,
-        body: &'tcx hir::Body<'tcx>,
-        _: Span,
-        def_id: rustc_span::def_id::LocalDefId,
-    ) {
-        if !body.value.span.edition().at_least_rust_2024() {
-            Self::check_fn_or_closure(cx, fn_kind, body, def_id);
-        }
-    }
-}
-
-struct LintVisitor<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    // We only record locals that have significant drops
-    locals: Vec<Span>,
-}
-
-struct LocalCollector<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    locals: &'a mut Vec<Span>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LocalCollector<'a, 'tcx> {
-    type Result = ();
-    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
-        if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind {
-            let ty = self.cx.typeck_results().node_type(id);
-            if ty.has_significant_drop(self.cx.tcx, self.cx.typing_env()) {
-                self.locals.push(ident.span);
-            }
-            if let Some(pat) = pat {
-                self.visit_pat(pat);
-            }
-        } else {
-            intravisit::walk_pat(self, pat);
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> {
-    fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
-        let mut locals = <_>::default();
-        swap(&mut locals, &mut self.locals);
-        self.check_block_inner(block);
-        swap(&mut locals, &mut self.locals);
-    }
-    fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
-        LocalCollector { cx: self.cx, locals: &mut self.locals }.visit_local(local);
-    }
-}
-
-impl<'a, 'tcx> LintVisitor<'a, 'tcx> {
-    fn check_block_inner(&mut self, block: &Block<'tcx>) {
-        if block.span.at_least_rust_2024() {
-            // We only lint up to Edition 2021
-            return;
-        }
-        let Some(tail_expr) = block.expr else { return };
-        for stmt in block.stmts {
-            match stmt.kind {
-                StmtKind::Let(let_stmt) => self.visit_local(let_stmt),
-                StmtKind::Item(_) => {}
-                StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e),
-            }
-        }
-        if self.locals.is_empty() {
-            return;
-        }
-        LintTailExpr { cx: self.cx, locals: &self.locals, is_root_tail_expr: true }
-            .visit_expr(tail_expr);
-    }
-}
-
-struct LintTailExpr<'a, 'tcx> {
-    cx: &'a LateContext<'tcx>,
-    is_root_tail_expr: bool,
-    locals: &'a [Span],
-}
-
-impl<'a, 'tcx> LintTailExpr<'a, 'tcx> {
-    fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool {
-        loop {
-            match expr.kind {
-                ExprKind::Index(access, _, _) | ExprKind::Field(access, _) => expr = access,
-                ExprKind::AddrOf(_, _, referee) | ExprKind::Unary(UnOp::Deref, referee) => {
-                    expr = referee
-                }
-                ExprKind::Path(_)
-                    if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind
-                        && let [local, ..] = path.segments
-                        && let Res::Local(_) = local.res =>
-                {
-                    return true;
-                }
-                _ => return false,
-            }
-        }
-    }
-
-    fn expr_generates_nonlocal_droppy_value(&self, expr: &Expr<'tcx>) -> bool {
-        if Self::expr_eventually_point_into_local(expr) {
-            return false;
-        }
-        self.cx
-            .typeck_results()
-            .expr_ty(expr)
-            .has_significant_drop(self.cx.tcx, self.cx.typing_env())
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> {
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if self.is_root_tail_expr {
-            self.is_root_tail_expr = false;
-        } else if self.expr_generates_nonlocal_droppy_value(expr) {
-            self.cx.tcx.emit_node_span_lint(
-                TAIL_EXPR_DROP_ORDER,
-                expr.hir_id,
-                expr.span,
-                TailExprDropOrderLint { spans: self.locals.to_vec() },
-            );
-            return;
-        }
-        match expr.kind {
-            ExprKind::Match(scrutinee, _, _) => self.visit_expr(scrutinee),
-
-            ExprKind::ConstBlock(_)
-            | ExprKind::Array(_)
-            | ExprKind::Break(_, _)
-            | ExprKind::Continue(_)
-            | ExprKind::Ret(_)
-            | ExprKind::Become(_)
-            | ExprKind::Yield(_, _)
-            | ExprKind::InlineAsm(_)
-            | ExprKind::If(_, _, _)
-            | ExprKind::Loop(_, _, _, _)
-            | ExprKind::Closure(_)
-            | ExprKind::DropTemps(_)
-            | ExprKind::OffsetOf(_, _)
-            | ExprKind::Assign(_, _, _)
-            | ExprKind::AssignOp(_, _, _)
-            | ExprKind::Lit(_)
-            | ExprKind::Err(_) => {}
-
-            ExprKind::MethodCall(_, _, _, _)
-            | ExprKind::Call(_, _)
-            | ExprKind::Type(_, _)
-            | ExprKind::Tup(_)
-            | ExprKind::Binary(_, _, _)
-            | ExprKind::Unary(_, _)
-            | ExprKind::Path(_)
-            | ExprKind::Let(_)
-            | ExprKind::Cast(_, _)
-            | ExprKind::Field(_, _)
-            | ExprKind::Index(_, _, _)
-            | ExprKind::AddrOf(_, _, _)
-            | ExprKind::Struct(_, _, _)
-            | ExprKind::Repeat(_, _) => intravisit::walk_expr(self, expr),
-
-            ExprKind::Block(_, _) => {
-                // We do not lint further because the drop order stays the same inside the block
-            }
-        }
-    }
-    fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
-        LintVisitor { cx: self.cx, locals: <_>::default() }.check_block_inner(block);
-    }
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_tail_expr_drop_order)]
-struct TailExprDropOrderLint {
-    #[label]
-    pub spans: Vec<Span>,
-}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 313a7badf19..9036741e078 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -101,6 +101,7 @@ declare_lint_pass! {
         SINGLE_USE_LIFETIMES,
         SOFT_UNSTABLE,
         STABLE_FEATURES,
+        TAIL_EXPR_DROP_ORDER,
         TEST_UNSTABLE_LINT,
         TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
         TRIVIAL_CASTS,
@@ -4995,6 +4996,83 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
+    /// that runs a custom `Drop` destructor.
+    /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior.
+    /// This lint detects those cases and provides you information on those values and their custom destructor implementations.
+    /// Your discretion on this information is required.
+    ///
+    /// ### Example
+    /// ```rust,edition2021
+    /// #![warn(tail_expr_drop_order)]
+    /// struct Droppy(i32);
+    /// impl Droppy {
+    ///     fn get(&self) -> i32 {
+    ///         self.0
+    ///     }
+    /// }
+    /// impl Drop for Droppy {
+    ///     fn drop(&mut self) {
+    ///         // This is a custom destructor and it induces side-effects that is observable
+    ///         // especially when the drop order at a tail expression changes.
+    ///         println!("loud drop {}", self.0);
+    ///     }
+    /// }
+    /// fn edition_2021() -> i32 {
+    ///     let another_droppy = Droppy(0);
+    ///     Droppy(1).get()
+    /// }
+    /// fn main() {
+    ///     edition_2021();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In tail expression of blocks or function bodies,
+    /// values of type with significant `Drop` implementation has an ill-specified drop order
+    /// before Edition 2024 so that they are dropped only after dropping local variables.
+    /// Edition 2024 introduces a new rule with drop orders for them,
+    /// so that they are dropped first before dropping local variables.
+    ///
+    /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary
+    /// implementation of the `Drop` trait on the type, with exceptions including `Vec`,
+    /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise
+    /// so long that the generic types have no significant destructor recursively.
+    /// In other words, a type has a significant drop destructor when it has a `Drop` implementation
+    /// or its destructor invokes a significant destructor on a type.
+    /// Since we cannot completely reason about the change by just inspecting the existence of
+    /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default.
+    ///
+    /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy`
+    /// does in Edition 2024.
+    /// No fix will be proposed by this lint.
+    /// However, the most probable fix is to hoist `Droppy` into its own local variable binding.
+    /// ```rust
+    /// struct Droppy(i32);
+    /// impl Droppy {
+    ///     fn get(&self) -> i32 {
+    ///         self.0
+    ///     }
+    /// }
+    /// fn edition_2024() -> i32 {
+    ///     let value = Droppy(0);
+    ///     let another_droppy = Droppy(1);
+    ///     value.get()
+    /// }
+    /// ```
+    pub TAIL_EXPR_DROP_ORDER,
+    Allow,
+    "Detect and warn on significant change in drop order in tail expression location",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+        reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>",
+    };
+}
+
+declare_lint! {
     /// The `rust_2024_guarded_string_incompatible_syntax` lint detects `#` tokens
     /// that will be parsed as part of a guarded string literal in Rust 2024.
     ///
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index cece700b4dd..12519be9870 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+libc = "0.2"
 libloading = "0.8.0"
 odht = { version = "0.3.1", features = ["nightly"] }
 rustc_abi = { path = "../rustc_abi" }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index ca16a66763a..a611e8010be 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -540,6 +540,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 Some(cnum)
             }
             Err(err) => {
+                debug!("failed to resolve crate {} {:?}", name, dep_kind);
                 let missing_core =
                     self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
                 err.report(self.sess, span, missing_core);
@@ -588,6 +589,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             match self.load(&mut locator)? {
                 Some(res) => (res, None),
                 None => {
+                    info!("falling back to loading proc_macro");
                     dep_kind = CrateDepKind::MacrosOnly;
                     match self.load_proc_macro(&mut locator, path_kind, host_hash)? {
                         Some(res) => res,
@@ -599,6 +601,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         match result {
             (LoadResult::Previous(cnum), None) => {
+                info!("library for `{}` was loaded previously", name);
                 // When `private_dep` is none, it indicates the directly dependent crate. If it is
                 // not specified by `--extern` on command line parameters, it may be
                 // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
@@ -613,6 +616,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 Ok(cnum)
             }
             (LoadResult::Loaded(library), host_library) => {
+                info!("register newly loaded library for `{}`", name);
                 self.register_crate(host_library, root, library, dep_kind, name, private_dep)
             }
             _ => panic!(),
@@ -696,7 +700,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         stable_crate_id: StableCrateId,
     ) -> Result<&'static [ProcMacro], CrateError> {
         let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
-        Ok(unsafe { *load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name)? })
+        debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
+
+        unsafe {
+            let result = load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name);
+            match result {
+                Ok(result) => {
+                    debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
+                    Ok(*result)
+                }
+                Err(err) => {
+                    debug!(
+                        "failed to dlsym proc_macros {} for symbol `{}`",
+                        path.display(),
+                        sym_name
+                    );
+                    Err(err.into())
+                }
+            }
+        }
     }
 
     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@@ -1141,6 +1163,29 @@ fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
     e.sources().map(|e| format!(": {e}")).collect()
 }
 
+fn attempt_load_dylib(path: &Path) -> Result<libloading::Library, libloading::Error> {
+    #[cfg(target_os = "aix")]
+    if let Some(ext) = path.extension()
+        && ext.eq("a")
+    {
+        // On AIX, we ship all libraries as .a big_af archive
+        // the expected format is lib<name>.a(libname.so) for the actual
+        // dynamic library
+        let library_name = path.file_stem().expect("expect a library name");
+        let mut archive_member = OsString::from("a(");
+        archive_member.push(library_name);
+        archive_member.push(".so)");
+        let new_path = path.with_extension(archive_member);
+
+        // On AIX, we need RTLD_MEMBER to dlopen an archived shared
+        let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER;
+        return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) }
+            .map(|lib| lib.into());
+    }
+
+    unsafe { libloading::Library::new(&path) }
+}
+
 // On Windows the compiler would sometimes intermittently fail to open the
 // proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
 // system still holds a lock on the file, so we retry a few times before calling it
@@ -1151,7 +1196,8 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, S
     let mut last_error = None;
 
     for attempt in 0..max_attempts {
-        match unsafe { libloading::Library::new(&path) } {
+        debug!("Attempt to load proc-macro `{}`.", path.display());
+        match attempt_load_dylib(path) {
             Ok(lib) => {
                 if attempt > 0 {
                     debug!(
@@ -1165,6 +1211,7 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, S
             Err(err) => {
                 // Only try to recover from this specific error.
                 if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
+                    debug!("Failed to load proc-macro `{}`. Not retrying", path.display());
                     let err = format_dlopen_err(&err);
                     // We include the path of the dylib in the error ourselves, so
                     // if it's in the error, we strip it.
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 0b53e5eeaa8..d59ec7af6ec 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -847,7 +847,10 @@ fn get_metadata_section<'p>(
         )));
     };
     match blob.check_compatibility(cfg_version) {
-        Ok(()) => Ok(blob),
+        Ok(()) => {
+            debug!("metadata blob read okay");
+            Ok(blob)
+        }
         Err(None) => Err(MetadataError::LoadFailure(format!(
             "invalid metadata version found: {}",
             filename.display()
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 045fd0565ba..a89096beb8c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -275,7 +275,7 @@ provide! { tcx, def_id, other, cdata,
     defaultness => { table_direct }
     constness => { table_direct }
     const_conditions => { table }
-    implied_const_bounds => { table_defaulted_array }
+    explicit_implied_const_bounds => { table_defaulted_array }
     coerce_unsized_info => {
         Ok(cdata
             .root
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index b5391247cea..8378e7c6e9b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1463,8 +1463,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record_array!(self.tables.module_children_non_reexports[def_id] <-
                     module_children.iter().map(|child| child.res.def_id().index));
                 if self.tcx.is_const_trait(def_id) {
-                    record_defaulted_array!(self.tables.implied_const_bounds[def_id]
-                        <- self.tcx.implied_const_bounds(def_id).skip_binder());
+                    record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                        <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
                 }
             }
             if let DefKind::TraitAlias = def_kind {
@@ -1532,6 +1532,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 self.encode_explicit_item_super_predicates(def_id);
                 record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id));
                 self.encode_precise_capturing_args(def_id);
+                if tcx.is_conditionally_const(def_id) {
+                    record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                        <- tcx.explicit_implied_const_bounds(def_id).skip_binder());
+                }
             }
             if tcx.impl_method_has_trait_impl_trait_tys(def_id)
                 && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
@@ -1654,8 +1658,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     self.encode_explicit_item_bounds(def_id);
                     self.encode_explicit_item_super_predicates(def_id);
                     if tcx.is_conditionally_const(def_id) {
-                        record_defaulted_array!(self.tables.implied_const_bounds[def_id]
-                            <- self.tcx.implied_const_bounds(def_id).skip_binder());
+                        record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                            <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
                     }
                 }
             }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 58f58efb116..4a8f8521b4f 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -391,7 +391,7 @@ define_tables! {
     inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
-    implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>,
+    explicit_implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
     opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index b20673fe8da..7a91bfad483 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -68,6 +68,17 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family
+    /// trait, if it is defined.
+    pub fn async_fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> {
+        let items = self.lang_items();
+        match kind {
+            ty::ClosureKind::Fn => items.async_fn_trait(),
+            ty::ClosureKind::FnMut => items.async_fn_mut_trait(),
+            ty::ClosureKind::FnOnce => items.async_fn_once_trait(),
+        }
+    }
+
     /// Returns `true` if `id` is a `DefId` of [`Fn`], [`FnMut`] or [`FnOnce`] traits.
     pub fn is_fn_trait(self, id: DefId) -> bool {
         self.fn_trait_kind_from_def_id(id).is_some()
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 4e44de33611..114211b27c1 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -236,6 +236,11 @@ pub struct ScopeTree {
     /// during type check based on a traversal of the AST.
     pub rvalue_candidates: HirIdMap<RvalueCandidateType>,
 
+    /// Backwards incompatible scoping that will be introduced in future editions.
+    /// This information is used later for linting to identify locals and
+    /// temporary values that will receive backwards-incompatible drop orders.
+    pub backwards_incompatible_scope: UnordMap<hir::ItemLocalId, Scope>,
+
     /// If there are any `yield` nested within a scope, this map
     /// stores the `Span` of the last one and its index in the
     /// postorder of the Visitor traversal on the HIR.
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index f0e2b7a376c..2bfcd0a6227 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -834,6 +834,11 @@ impl Debug for Statement<'_> {
             Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
             ConstEvalCounter => write!(fmt, "ConstEvalCounter"),
             Nop => write!(fmt, "nop"),
+            BackwardIncompatibleDropHint { ref place, reason: _ } => {
+                // For now, we don't record the reason because there is only one use case,
+                // which is to report breaking change in drop order by Edition 2024
+                write!(fmt, "backward incompatible drop({place:?})")
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 2083279e128..fea940ea47c 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -432,6 +432,18 @@ pub enum StatementKind<'tcx> {
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
+
+    /// Marker statement indicating where `place` would be dropped.
+    /// This is semantically equivalent to `Nop`, so codegen and MIRI should interpret this
+    /// statement as such.
+    /// The only use case of this statement is for linting in MIR to detect temporary lifetime
+    /// changes.
+    BackwardIncompatibleDropHint {
+        /// Place to drop
+        place: Box<Place<'tcx>>,
+        /// Reason for backward incompatibility
+        reason: BackwardIncompatibleDropReason,
+    },
 }
 
 impl StatementKind<'_> {
@@ -452,6 +464,7 @@ impl StatementKind<'_> {
             StatementKind::Intrinsic(..) => "Intrinsic",
             StatementKind::ConstEvalCounter => "ConstEvalCounter",
             StatementKind::Nop => "Nop",
+            StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint",
         }
     }
 }
@@ -897,6 +910,21 @@ pub enum TerminatorKind<'tcx> {
     },
 }
 
+#[derive(
+    Clone,
+    Debug,
+    TyEncodable,
+    TyDecodable,
+    Hash,
+    HashStable,
+    PartialEq,
+    TypeFoldable,
+    TypeVisitable
+)]
+pub enum BackwardIncompatibleDropReason {
+    Edition2024,
+}
+
 impl TerminatorKind<'_> {
     /// Returns a simple string representation of a `TerminatorKind` variant, independent of any
     /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`).
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 9f9ee8497b6..62c340d99e3 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -452,6 +452,7 @@ macro_rules! make_mir_visitor {
                     }
                     StatementKind::ConstEvalCounter => {}
                     StatementKind::Nop => {}
+                    StatementKind::BackwardIncompatibleDropHint { .. } => {}
                 }
             }
 
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 8fd99303622..970dc72e1ff 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -360,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) {
     }
 }
 
+impl<'tcx> Key for ty::ParamEnvAnd<'tcx, Ty<'tcx>> {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for ty::TraitRef<'tcx> {
     type Cache<V> = DefaultCache<Self, V>;
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 9ae519dfe7e..76338be33aa 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -697,7 +697,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query implied_const_bounds(
+    query explicit_implied_const_bounds(
         key: DefId
     ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
         desc { |tcx| "computing the implied `~const` bounds for `{}`",
@@ -1448,6 +1448,28 @@ rustc_queries! {
         cache_on_disk_if { false }
     }
 
+    /// Returns a list of types which (a) have a potentially significant destructor
+    /// and (b) may be dropped as a result of dropping a value of some type `ty`
+    /// (in the given environment).
+    ///
+    /// The idea of "significant" drop is somewhat informal and is used only for
+    /// diagnostics and edition migrations. The idea is that a significant drop may have
+    /// some visible side-effect on execution; freeing memory is NOT considered a side-effect.
+    /// The rules are as follows:
+    /// * Type with no explicit drop impl do not have significant drop.
+    /// * Types with a drop impl are assumed to have significant drop unless they have a `#[rustc_insignificant_dtor]` annotation.
+    ///
+    /// Note that insignificant drop is a "shallow" property. A type like `Vec<LockGuard>` does not
+    /// have significant drop but the type `LockGuard` does, and so if `ty  = Vec<LockGuard>`
+    /// then the return value would be `&[LockGuard]`.
+    /// *IMPORTANT*: *DO NOT* run this query before promoted MIR body is constructed,
+    /// because this query partially depends on that query.
+    /// Otherwise, there is a risk of query cycles.
+    query list_significant_drop_tys(ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx ty::List<Ty<'tcx>> {
+        desc { |tcx| "computing when `{}` has a significant destructor", ty.value }
+        cache_on_disk_if { false }
+    }
+
     /// Computes the layout of a type. Note that this implicitly
     /// executes in "reveal all" mode, and will normalize the input type.
     query layout_of(
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 8f26e05cb72..9cf6bc1b777 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -247,13 +247,24 @@ pub struct Expr<'tcx> {
     pub ty: Ty<'tcx>,
 
     /// The lifetime of this expression if it should be spilled into a
-    /// temporary; should be `None` only if in a constant context
-    pub temp_lifetime: Option<region::Scope>,
+    /// temporary
+    pub temp_lifetime: TempLifetime,
 
     /// span of the expression in the source
     pub span: Span,
 }
 
+/// Temporary lifetime information for THIR expressions
+#[derive(Clone, Copy, Debug, HashStable)]
+pub struct TempLifetime {
+    /// Lifetime for temporaries as expected.
+    /// This should be `None` in a constant context.
+    pub temp_lifetime: Option<region::Scope>,
+    /// If `Some(lt)`, indicates that the lifetime of this temporary will change to `lt` in a future edition.
+    /// If `None`, then no changes are expected, or lints are disabled.
+    pub backwards_incompatible: Option<region::Scope>,
+}
+
 #[derive(Clone, Debug, HashStable)]
 pub enum ExprKind<'tcx> {
     /// `Scope`s are used to explicitly mark destruction scopes,
@@ -645,7 +656,7 @@ impl<'tcx> Pat<'tcx> {
             | Binding { subpattern: Some(subpattern), .. }
             | Deref { subpattern }
             | DerefPattern { subpattern, .. }
-            | InlineConstant { subpattern, .. } => subpattern.walk_(it),
+            | ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
             }
@@ -788,12 +799,17 @@ pub enum PatKind<'tcx> {
         value: mir::Const<'tcx>,
     },
 
-    /// Inline constant found while lowering a pattern.
-    InlineConstant {
-        /// [LocalDefId] of the constant, we need this so that we have a
+    /// Pattern obtained by converting a constant (inline or named) to its pattern
+    /// representation using `const_to_pat`.
+    ExpandedConstant {
+        /// [DefId] of the constant, we need this so that we have a
         /// reference that can be used by unsafety checking to visit nested
-        /// unevaluated constants.
-        def: LocalDefId,
+        /// unevaluated constants and for diagnostics. If the `DefId` doesn't
+        /// correspond to a local crate, it points at the `const` item.
+        def_id: DefId,
+        /// If `false`, then `def_id` points at a `const` item, otherwise it
+        /// corresponds to a local inline const.
+        is_inline: bool,
         /// If the inline constant is used in a range pattern, this subpattern
         /// represents the range (if both ends are inline constants, there will
         /// be multiple InlineConstant wrappers).
@@ -1087,7 +1103,7 @@ mod size_asserts {
     use super::*;
     // tidy-alphabetical-start
     static_assert_size!(Block, 48);
-    static_assert_size!(Expr<'_>, 64);
+    static_assert_size!(Expr<'_>, 72);
     static_assert_size!(ExprKind<'_>, 40);
     static_assert_size!(Pat<'_>, 64);
     static_assert_size!(PatKind<'_>, 48);
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 36f0e3d890c..81202a6eaad 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -247,7 +247,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
             }
         }
         Constant { value: _ } => {}
-        InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
+        ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
             for subpattern in prefix.iter() {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index ad42eacf823..55c29825fbc 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -393,12 +393,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         )
     }
 
-    fn implied_const_bounds(
+    fn explicit_implied_const_bounds(
         self,
         def_id: DefId,
     ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
         ty::EarlyBinder::bind(
-            self.implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
+            self.explicit_implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
         )
     }
 
@@ -602,19 +602,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.coroutine_is_async_gen(coroutine_def_id)
     }
 
-    // We don't use `TypingEnv` here as it's only defined in `rustc_middle` and
-    // `rustc_next_trait_solver` shouldn't have to know about it.
-    fn layout_is_pointer_like(
-        self,
-        typing_mode: ty::TypingMode<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> bool {
-        let typing_env = ty::TypingEnv { typing_mode, param_env };
-        self.layout_of(self.erase_regions(typing_env).as_query_input(self.erase_regions(ty)))
-            .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout))
-    }
-
     type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>;
     fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
         self.unsizing_params_for_adt(adt_def_id)
@@ -688,7 +675,6 @@ bidirectional_lang_item_map! {
     Metadata,
     Option,
     PointeeTrait,
-    PointerLike,
     Poll,
     Sized,
     TransmuteTrait,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index dd8286c8eb9..2bc055453a4 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2110,7 +2110,13 @@ impl<'tcx> TyCtxt<'tcx> {
                     _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
                 }
             }
-            DefKind::Closure | DefKind::OpaqueTy => {
+            DefKind::OpaqueTy => match self.opaque_ty_origin(def_id) {
+                hir::OpaqueTyOrigin::FnReturn { parent, .. } => self.is_conditionally_const(parent),
+                hir::OpaqueTyOrigin::AsyncFn { .. } => false,
+                // FIXME(const_trait_impl): ATPITs could be conditionally const?
+                hir::OpaqueTyOrigin::TyAlias { .. } => false,
+            },
+            DefKind::Closure => {
                 // Closures and RPITs will eventually have const conditions
                 // for `~const` bounds.
                 false
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 039c988f5c9..cd4123f0a3f 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -16,8 +16,8 @@ use rustc_hir::definitions::{DefKey, DefPathDataName};
 use rustc_macros::{Lift, extension};
 use rustc_session::Limit;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
-use rustc_span::FileNameDisplayPreference;
 use rustc_span::symbol::{Ident, Symbol, kw};
+use rustc_span::{FileNameDisplayPreference, sym};
 use rustc_type_ir::{Upcast as _, elaborate};
 use smallvec::SmallVec;
 
@@ -26,8 +26,8 @@ use super::*;
 use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::query::{IntoQueryParam, Providers};
 use crate::ty::{
-    ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TypeFoldable,
-    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    ConstInt, Expr, GenericArgKind, ParamConst, ScalarInt, Term, TermKind, TraitPredicate,
+    TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 
 macro_rules! p {
@@ -993,10 +993,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
             match bound_predicate.skip_binder() {
                 ty::ClauseKind::Trait(pred) => {
-                    let trait_ref = bound_predicate.rebind(pred.trait_ref);
-
                     // Don't print `+ Sized`, but rather `+ ?Sized` if absent.
-                    if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
+                    if tcx.is_lang_item(pred.def_id(), LangItem::Sized) {
                         match pred.polarity {
                             ty::PredicatePolarity::Positive => {
                                 has_sized_bound = true;
@@ -1007,24 +1005,22 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     }
 
                     self.insert_trait_and_projection(
-                        trait_ref,
-                        pred.polarity,
+                        bound_predicate.rebind(pred),
                         None,
                         &mut traits,
                         &mut fn_traits,
                     );
                 }
                 ty::ClauseKind::Projection(pred) => {
-                    let proj_ref = bound_predicate.rebind(pred);
-                    let trait_ref = proj_ref.required_poly_trait_ref(tcx);
-
-                    // Projection type entry -- the def-id for naming, and the ty.
-                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
+                    let proj = bound_predicate.rebind(pred);
+                    let trait_ref = proj.map_bound(|proj| TraitPredicate {
+                        trait_ref: proj.projection_term.trait_ref(tcx),
+                        polarity: ty::PredicatePolarity::Positive,
+                    });
 
                     self.insert_trait_and_projection(
                         trait_ref,
-                        ty::PredicatePolarity::Positive,
-                        Some(proj_ty),
+                        Some((proj.projection_def_id(), proj.term())),
                         &mut traits,
                         &mut fn_traits,
                     );
@@ -1042,88 +1038,66 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
         let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound;
 
-        for (fn_once_trait_ref, entry) in fn_traits {
+        for ((bound_args, is_async), entry) in fn_traits {
             write!(self, "{}", if first { "" } else { " + " })?;
             write!(self, "{}", if paren_needed { "(" } else { "" })?;
 
-            self.wrap_binder(&fn_once_trait_ref, |trait_ref, cx| {
-                define_scoped_cx!(cx);
-                // Get the (single) generic ty (the args) of this FnOnce trait ref.
-                let generics = tcx.generics_of(trait_ref.def_id);
-                let own_args = generics.own_args_no_defaults(tcx, trait_ref.args);
-
-                match (entry.return_ty, own_args[0].expect_ty()) {
-                    // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
-                    // a return type.
-                    (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
-                        let name = if entry.fn_trait_ref.is_some() {
-                            "Fn"
-                        } else if entry.fn_mut_trait_ref.is_some() {
-                            "FnMut"
-                        } else {
-                            "FnOnce"
-                        };
-
-                        p!(write("{}(", name));
+            let trait_def_id = if is_async {
+                tcx.async_fn_trait_kind_to_def_id(entry.kind).expect("expected AsyncFn lang items")
+            } else {
+                tcx.fn_trait_kind_to_def_id(entry.kind).expect("expected Fn lang items")
+            };
 
-                        for (idx, ty) in arg_tys.tuple_fields().iter().enumerate() {
-                            if idx > 0 {
-                                p!(", ");
-                            }
-                            p!(print(ty));
-                        }
+            if let Some(return_ty) = entry.return_ty {
+                self.wrap_binder(&bound_args, |args, cx| {
+                    define_scoped_cx!(cx);
+                    p!(write("{}", tcx.item_name(trait_def_id)));
+                    p!("(");
 
-                        p!(")");
-                        if let Some(ty) = return_ty.skip_binder().as_type() {
-                            if !ty.is_unit() {
-                                p!(" -> ", print(return_ty));
-                            }
+                    for (idx, ty) in args.iter().enumerate() {
+                        if idx > 0 {
+                            p!(", ");
                         }
-                        p!(write("{}", if paren_needed { ")" } else { "" }));
-
-                        first = false;
+                        p!(print(ty));
                     }
-                    // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
-                    // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
-                    _ => {
-                        if entry.has_fn_once {
-                            traits
-                                .entry((fn_once_trait_ref, ty::PredicatePolarity::Positive))
-                                .or_default()
-                                .extend(
-                                    // Group the return ty with its def id, if we had one.
-                                    entry.return_ty.map(|ty| {
-                                        (tcx.require_lang_item(LangItem::FnOnceOutput, None), ty)
-                                    }),
-                                );
-                        }
-                        if let Some(trait_ref) = entry.fn_mut_trait_ref {
-                            traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default();
-                        }
-                        if let Some(trait_ref) = entry.fn_trait_ref {
-                            traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default();
+
+                    p!(")");
+                    if let Some(ty) = return_ty.skip_binder().as_type() {
+                        if !ty.is_unit() {
+                            p!(" -> ", print(return_ty));
                         }
                     }
-                }
+                    p!(write("{}", if paren_needed { ")" } else { "" }));
 
-                Ok(())
-            })?;
+                    first = false;
+                    Ok(())
+                })?;
+            } else {
+                // Otherwise, render this like a regular trait.
+                traits.insert(
+                    bound_args.map_bound(|args| ty::TraitPredicate {
+                        polarity: ty::PredicatePolarity::Positive,
+                        trait_ref: ty::TraitRef::new(tcx, trait_def_id, [Ty::new_tup(tcx, args)]),
+                    }),
+                    FxIndexMap::default(),
+                );
+            }
         }
 
         // Print the rest of the trait types (that aren't Fn* family of traits)
-        for ((trait_ref, polarity), assoc_items) in traits {
+        for (trait_pred, assoc_items) in traits {
             write!(self, "{}", if first { "" } else { " + " })?;
 
-            self.wrap_binder(&trait_ref, |trait_ref, cx| {
+            self.wrap_binder(&trait_pred, |trait_pred, cx| {
                 define_scoped_cx!(cx);
 
-                if polarity == ty::PredicatePolarity::Negative {
+                if trait_pred.polarity == ty::PredicatePolarity::Negative {
                     p!("!");
                 }
-                p!(print(trait_ref.print_only_trait_name()));
+                p!(print(trait_pred.trait_ref.print_only_trait_name()));
 
-                let generics = tcx.generics_of(trait_ref.def_id);
-                let own_args = generics.own_args_no_defaults(tcx, trait_ref.args);
+                let generics = tcx.generics_of(trait_pred.def_id());
+                let own_args = generics.own_args_no_defaults(tcx, trait_pred.trait_ref.args);
 
                 if !own_args.is_empty() || !assoc_items.is_empty() {
                     let mut first = true;
@@ -1230,51 +1204,48 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
     /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
     fn insert_trait_and_projection(
         &mut self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        polarity: ty::PredicatePolarity,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
         traits: &mut FxIndexMap<
-            (ty::PolyTraitRef<'tcx>, ty::PredicatePolarity),
+            ty::PolyTraitPredicate<'tcx>,
             FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
         >,
-        fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+        fn_traits: &mut FxIndexMap<
+            (ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>>, bool),
+            OpaqueFnEntry<'tcx>,
+        >,
     ) {
-        let trait_def_id = trait_ref.def_id();
-
-        // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
-        // super-trait ref and record it there.
-        // We skip negative Fn* bounds since they can't use parenthetical notation anyway.
-        if polarity == ty::PredicatePolarity::Positive
-            && let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait()
-        {
-            // If we have a FnOnce, then insert it into
-            if trait_def_id == fn_once_trait {
-                let entry = fn_traits.entry(trait_ref).or_default();
-                // Optionally insert the return_ty as well.
-                if let Some((_, ty)) = proj_ty {
-                    entry.return_ty = Some(ty);
-                }
-                entry.has_fn_once = true;
-                return;
-            } else if self.tcx().is_lang_item(trait_def_id, LangItem::FnMut) {
-                let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref)
-                    .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
-                    .unwrap();
+        let tcx = self.tcx();
+        let trait_def_id = trait_pred.def_id();
 
-                fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref);
-                return;
-            } else if self.tcx().is_lang_item(trait_def_id, LangItem::Fn) {
-                let super_trait_ref = elaborate::supertraits(self.tcx(), trait_ref)
-                    .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
-                    .unwrap();
+        let fn_trait_and_async = if let Some(kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) {
+            Some((kind, false))
+        } else if let Some(kind) = tcx.async_fn_trait_kind_from_def_id(trait_def_id) {
+            Some((kind, true))
+        } else {
+            None
+        };
 
-                fn_traits.entry(super_trait_ref).or_default().fn_trait_ref = Some(trait_ref);
-                return;
+        if trait_pred.polarity() == ty::PredicatePolarity::Positive
+            && let Some((kind, is_async)) = fn_trait_and_async
+            && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
+        {
+            let entry = fn_traits
+                .entry((trait_pred.rebind(types), is_async))
+                .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None });
+            if kind.extends(entry.kind) {
+                entry.kind = kind;
+            }
+            if let Some((proj_def_id, proj_ty)) = proj_ty
+                && tcx.item_name(proj_def_id) == sym::Output
+            {
+                entry.return_ty = Some(proj_ty);
             }
+            return;
         }
 
         // Otherwise, just group our traits and projection types.
-        traits.entry((trait_ref, polarity)).or_default().extend(proj_ty);
+        traits.entry(trait_pred).or_default().extend(proj_ty);
     }
 
     fn pretty_print_inherent_projection(
@@ -3189,10 +3160,10 @@ define_print_and_forward_display! {
 
     TraitRefPrintSugared<'tcx> {
         if !with_reduced_queries()
-            && let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id)
+            && cx.tcx().trait_def(self.0.def_id).paren_sugar
             && let ty::Tuple(args) = self.0.args.type_at(1).kind()
         {
-            p!(write("{}", kind.as_str()), "(");
+            p!(write("{}", cx.tcx().item_name(self.0.def_id)), "(");
             for (i, arg) in args.iter().enumerate() {
                 if i > 0 {
                     p!(", ");
@@ -3415,11 +3386,7 @@ pub fn provide(providers: &mut Providers) {
     *providers = Providers { trimmed_def_paths, ..*providers };
 }
 
-#[derive(Default)]
 pub struct OpaqueFnEntry<'tcx> {
-    // The trait ref is already stored as a key, so just track if we have it as a real predicate
-    has_fn_once: bool,
-    fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
-    fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+    kind: ty::ClosureKind,
     return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
 }
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
index 37dcf7c0d64..57c2d7623d2 100644
--- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -18,15 +18,17 @@ impl RvalueScopes {
     }
 
     /// Returns the scope when the temp created by `expr_id` will be cleaned up.
+    /// It also emits a lint on potential backwards incompatible change to the temporary scope
+    /// which is *for now* always shortening.
     pub fn temporary_scope(
         &self,
         region_scope_tree: &ScopeTree,
         expr_id: hir::ItemLocalId,
-    ) -> Option<Scope> {
+    ) -> (Option<Scope>, Option<Scope>) {
         // Check for a designated rvalue scope.
         if let Some(&s) = self.map.get(&expr_id) {
             debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
-            return s;
+            return (s, None);
         }
 
         // Otherwise, locate the innermost terminating scope
@@ -34,27 +36,40 @@ impl RvalueScopes {
         // have an enclosing scope, hence no scope will be
         // returned.
         let mut id = Scope { id: expr_id, data: ScopeData::Node };
+        let mut backwards_incompatible = None;
 
         while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) {
             match p.data {
                 ScopeData::Destruction => {
                     debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
-                    return Some(id);
+                    return (Some(id), backwards_incompatible);
                 }
                 ScopeData::IfThenRescope => {
                     debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]");
-                    return Some(p);
+                    return (Some(p), backwards_incompatible);
                 }
                 ScopeData::Node
                 | ScopeData::CallSite
                 | ScopeData::Arguments
                 | ScopeData::IfThen
-                | ScopeData::Remainder(_) => id = p,
+                | ScopeData::Remainder(_) => {
+                    // If we haven't already passed through a backwards-incompatible node,
+                    // then check if we are passing through one now and record it if so.
+                    // This is for now only working for cases where a temporary lifetime is
+                    // *shortened*.
+                    if backwards_incompatible.is_none() {
+                        backwards_incompatible = region_scope_tree
+                            .backwards_incompatible_scope
+                            .get(&p.item_local_id())
+                            .copied();
+                    }
+                    id = p
+                }
             }
         }
 
         debug!("temporary_scope({expr_id:?}) = None");
-        None
+        (None, backwards_incompatible)
     }
 
     /// Make an association between a sub-expression and an extended lifetime
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 55149570dbc..5cb5990ae59 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -338,6 +338,13 @@ mir_build_unreachable_pattern = unreachable pattern
     .unreachable_covered_by_catchall = matches any value
     .unreachable_covered_by_one = matches all the relevant values
     .unreachable_covered_by_many = multiple earlier patterns match some of the same values
+    .unreachable_pattern_const_reexport_accessible = there is a constant of the same name imported in another scope, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it needs to be imported in the pattern's scope
+    .unreachable_pattern_wanted_const = you might have meant to pattern match against the value of {$is_typo ->
+        [true] similarly named constant
+        *[false] constant
+        } `{$const_name}` instead of introducing a new catch-all binding
+    .unreachable_pattern_const_inaccessible = there is a constant of the same name, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it is not accessible from this scope
+    .unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings
     .suggestion = remove the match arm
 
 mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index d08809ef67b..c3e9bd302de 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -144,12 +144,20 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
         let mut targets = Vec::new();
         for arm in rest {
             let arm = &self.thir[*arm];
-            let PatKind::Constant { value } = arm.pattern.kind else {
-                return Err(ParseError {
-                    span: arm.pattern.span,
-                    item_description: format!("{:?}", arm.pattern.kind),
-                    expected: "constant pattern".to_string(),
-                });
+            let value = match arm.pattern.kind {
+                PatKind::Constant { value } => value,
+                PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
+                    if let PatKind::Constant { value } = subpattern.kind =>
+                {
+                    value
+                }
+                _ => {
+                    return Err(ParseError {
+                        span: arm.pattern.span,
+                        item_description: format!("{:?}", arm.pattern.kind),
+                        expected: "constant pattern".to_string(),
+                    });
+                }
             };
             values.push(value.eval_bits(self.tcx, self.typing_env));
             targets.push(self.parse_block(arm.body)?);
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 159959d4f1f..0cab853196b 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -1,6 +1,5 @@
 //! See docs in build/expr/mod.rs
 
-use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use tracing::{debug, instrument};
@@ -9,6 +8,12 @@ use crate::build::expr::category::Category;
 use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Construct a temporary lifetime restricted to just the local scope
+    pub(crate) fn local_temp_lifetime(&self) -> TempLifetime {
+        let local_scope = self.local_scope();
+        TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None }
+    }
+
     /// Returns an operand suitable for use until the end of the current
     /// scope expression.
     ///
@@ -21,8 +26,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block: BasicBlock,
         expr_id: ExprId,
     ) -> BlockAnd<Operand<'tcx>> {
-        let local_scope = self.local_scope();
-        self.as_operand(block, Some(local_scope), expr_id, LocalInfo::Boring, NeedsTemporary::Maybe)
+        self.as_operand(
+            block,
+            self.local_temp_lifetime(),
+            expr_id,
+            LocalInfo::Boring,
+            NeedsTemporary::Maybe,
+        )
     }
 
     /// Returns an operand suitable for use until the end of the current scope expression and
@@ -80,8 +90,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block: BasicBlock,
         expr: ExprId,
     ) -> BlockAnd<Operand<'tcx>> {
-        let local_scope = self.local_scope();
-        self.as_call_operand(block, Some(local_scope), expr)
+        self.as_call_operand(block, self.local_temp_lifetime(), expr)
     }
 
     /// Compile `expr` into a value that can be used as an operand.
@@ -102,7 +111,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn as_operand(
         &mut self,
         mut block: BasicBlock,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         expr_id: ExprId,
         local_info: LocalInfo<'tcx>,
         needs_temporary: NeedsTemporary,
@@ -146,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn as_call_operand(
         &mut self,
         mut block: BasicBlock,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         expr_id: ExprId,
     ) -> BlockAnd<Operand<'tcx>> {
         let this = self;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 9f6e0735b48..6ce88cdc39d 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -6,7 +6,6 @@ use std::iter;
 use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::hir::place::{Projection as HirProjection, ProjectionKind as HirProjectionKind};
-use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind::BoundsCheck;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
@@ -598,7 +597,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         index: ExprId,
         mutability: Mutability,
         fake_borrow_temps: Option<&mut Vec<Local>>,
-        temp_lifetime: Option<region::Scope>,
+        temp_lifetime: TempLifetime,
         expr_span: Span,
         source_info: SourceInfo,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index a3fee38908b..3f89e337781 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -33,14 +33,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         expr_id: ExprId,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let local_scope = self.local_scope();
-        self.as_rvalue(block, Some(local_scope), expr_id)
+        self.as_rvalue(
+            block,
+            TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None },
+            expr_id,
+        )
     }
 
     /// Compile `expr`, yielding an rvalue.
     pub(crate) fn as_rvalue(
         &mut self,
         mut block: BasicBlock,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         expr_id: ExprId,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let this = self;
@@ -171,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     source_info,
                     kind: StatementKind::StorageLive(result),
                 });
-                if let Some(scope) = scope {
+                if let Some(scope) = scope.temp_lifetime {
                     // schedule a shallow free of that memory, lest we unwind:
                     this.schedule_drop_storage_and_value(expr_span, scope, result);
                 }
@@ -445,7 +449,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                         block = this.limit_capture_mutability(
                                             upvar_expr.span,
                                             upvar_expr.ty,
-                                            scope,
+                                            scope.temp_lifetime,
                                             block,
                                             arg,
                                         )
@@ -705,7 +709,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         value: ExprId,
-        scope: Option<region::Scope>,
+        scope: TempLifetime,
         outer_source_info: SourceInfo,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let this = self;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index b8b5e4634ed..466f67b1ba4 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -2,7 +2,6 @@
 
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::HirId;
-use rustc_middle::middle::region;
 use rustc_middle::middle::region::{Scope, ScopeData};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
@@ -17,7 +16,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn as_temp(
         &mut self,
         block: BasicBlock,
-        temp_lifetime: Option<region::Scope>,
+        temp_lifetime: TempLifetime,
         expr_id: ExprId,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
@@ -31,7 +30,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn as_temp_inner(
         &mut self,
         mut block: BasicBlock,
-        temp_lifetime: Option<region::Scope>,
+        temp_lifetime: TempLifetime,
         expr_id: ExprId,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
@@ -47,8 +46,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         let expr_ty = expr.ty;
-        let deduplicate_temps =
-            this.fixed_temps_scope.is_some() && this.fixed_temps_scope == temp_lifetime;
+        let deduplicate_temps = this.fixed_temps_scope.is_some()
+            && this.fixed_temps_scope == temp_lifetime.temp_lifetime;
         let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) {
             *temp_index
         } else {
@@ -76,7 +75,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     LocalInfo::BlockTailTemp(tail_info)
                 }
 
-                _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = temp_lifetime => {
+                _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) =
+                    temp_lifetime.temp_lifetime =>
+                {
                     LocalInfo::IfThenRescopeTemp {
                         if_then: HirId { owner: this.hir_id.owner, local_id: id },
                     }
@@ -117,7 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Anything with a shorter lifetime (e.g the `&foo()` in
                 // `bar(&foo())` or anything within a block will keep the
                 // regular drops just like runtime code.
-                if let Some(temp_lifetime) = temp_lifetime {
+                if let Some(temp_lifetime) = temp_lifetime.temp_lifetime {
                     this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage);
                 }
             }
@@ -125,10 +126,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         block = this.expr_into_dest(temp_place, block, expr_id).into_block();
 
-        if let Some(temp_lifetime) = temp_lifetime {
+        if let Some(temp_lifetime) = temp_lifetime.temp_lifetime {
             this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
         }
 
+        if let Some(backwards_incompatible) = temp_lifetime.backwards_incompatible {
+            this.schedule_backwards_incompatible_drop(expr_span, backwards_incompatible, temp);
+        }
+
         block.and(temp)
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 0dec56d21ae..bebb44faba6 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -139,7 +139,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // (#66975) Source could be a const of type `!`, so has to
                 // exist in the generated MIR.
                 unpack!(
-                    block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut)
+                    block =
+                        this.as_temp(block, this.local_temp_lifetime(), source, Mutability::Mut)
                 );
 
                 // This is an optimization. If the expression was a call then we already have an
@@ -321,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let is_union = adt_def.is_union();
                 let active_field_index = is_union.then(|| fields[0].name);
 
-                let scope = this.local_scope();
+                let scope = this.local_temp_lifetime();
 
                 // first process the set of fields that were provided
                 // (evaluating them in order given by user)
@@ -333,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             unpack!(
                                 block = this.as_operand(
                                     block,
-                                    Some(scope),
+                                    scope,
                                     f.expr,
                                     LocalInfo::AggregateTemp,
                                     NeedsTemporary::Maybe,
@@ -548,15 +549,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             ExprKind::Yield { value } => {
-                let scope = this.local_scope();
+                let scope = this.local_temp_lifetime();
                 let value = unpack!(
-                    block = this.as_operand(
-                        block,
-                        Some(scope),
-                        value,
-                        LocalInfo::Boring,
-                        NeedsTemporary::No
-                    )
+                    block =
+                        this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No)
                 );
                 let resume = this.cfg.start_new_block();
                 this.cfg.terminate(block, source_info, TerminatorKind::Yield {
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 02ca12028d3..15ee6dd014c 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -172,8 +172,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     None
                 };
 
-                let temp =
-                    unpack!(block = this.as_temp(block, statement_scope, expr_id, Mutability::Not));
+                let temp = unpack!(
+                    block = this.as_temp(
+                        block,
+                        TempLifetime {
+                            temp_lifetime: statement_scope,
+                            backwards_incompatible: None
+                        },
+                        expr_id,
+                        Mutability::Not
+                    )
+                );
 
                 if let Some(span) = adjusted_span {
                     this.local_decls[temp].source_info.span = span;
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index fcbf84a41d9..2815b390375 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 TestCase::Irrefutable { ascription: None, binding }
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
+                subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
+                default_irrefutable()
+            }
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
                 // Apply a type ascription for the inline constant to the value at `match_pair.place`
                 let ascription = place.map(|source| {
                     let span = pattern.span;
@@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                     })
                     .args;
                     let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                        def.to_def_id(),
+                        def_id,
                         ty::UserArgs { args, user_self_ty: None },
                     ));
                     let annotation = ty::CanonicalUserTypeAnnotation {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index a62d4e9d873..5791460a6b1 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -202,8 +202,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Increment the decision depth, in case we encounter boolean expressions
                 // further down.
                 this.mcdc_increment_depth_if_enabled();
-                let place =
-                    unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability));
+                let place = unpack!(
+                    block = this.as_temp(
+                        block,
+                        TempLifetime {
+                            temp_lifetime: Some(temp_scope),
+                            backwards_incompatible: None
+                        },
+                        expr_id,
+                        mutability
+                    )
+                );
                 this.mcdc_decrement_depth_if_enabled();
 
                 let operand = Operand::Move(Place::from(place));
@@ -917,7 +926,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
             }
 
-            PatKind::InlineConstant { ref subpattern, .. } => {
+            PatKind::ExpandedConstant { ref subpattern, .. } => {
                 self.visit_primary_bindings(subpattern, pattern_user_ty, f)
             }
 
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index e63fbeeac66..636e47b7ad2 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -89,7 +89,7 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::{ExprId, LintLevel};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty};
 use rustc_session::lint::Level;
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, Span};
@@ -151,6 +151,9 @@ struct DropData {
 
     /// Whether this is a value Drop or a StorageDead.
     kind: DropKind,
+
+    /// Whether this is a backwards-incompatible drop lint
+    backwards_incompatible_lint: bool,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -274,8 +277,12 @@ impl DropTree {
         // represents the block in the tree that should be jumped to once all
         // of the required drops have been performed.
         let fake_source_info = SourceInfo::outermost(DUMMY_SP);
-        let fake_data =
-            DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
+        let fake_data = DropData {
+            source_info: fake_source_info,
+            local: Local::MAX,
+            kind: DropKind::Storage,
+            backwards_incompatible_lint: false,
+        };
         let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]);
         Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() }
     }
@@ -763,7 +770,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let local =
                         place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
 
-                    Some(DropData { source_info, local, kind: DropKind::Value })
+                    Some(DropData {
+                        source_info,
+                        local,
+                        kind: DropKind::Value,
+                        backwards_incompatible_lint: false,
+                    })
                 }
                 Operand::Constant(_) => None,
             })
@@ -1019,9 +1031,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 if local.index() <= self.arg_count {
                     span_bug!(
                         span,
-                        "`schedule_drop` called with local {:?} and arg_count {}",
+                        "`schedule_drop` called with body argument {:?} \
+                        but its storage does not require a drop",
                         local,
-                        self.arg_count,
                     )
                 }
                 false
@@ -1089,6 +1101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
                     local,
                     kind: drop_kind,
+                    backwards_incompatible_lint: false,
                 });
 
                 return;
@@ -1098,6 +1111,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
     }
 
+    /// Schedule emission of a backwards incompatible drop lint hint.
+    /// Applicable only to temporary values for now.
+    pub(crate) fn schedule_backwards_incompatible_drop(
+        &mut self,
+        span: Span,
+        region_scope: region::Scope,
+        local: Local,
+    ) {
+        if !self.local_decls[local].ty.has_significant_drop(self.tcx, ty::TypingEnv {
+            typing_mode: ty::TypingMode::non_body_analysis(),
+            param_env: self.param_env,
+        }) {
+            return;
+        }
+        for scope in self.scopes.scopes.iter_mut().rev() {
+            // Since we are inserting linting MIR statement, we have to invalidate the caches
+            scope.invalidate_cache();
+            if scope.region_scope == region_scope {
+                let region_scope_span = region_scope.span(self.tcx, self.region_scope_tree);
+                let scope_end = self.tcx.sess.source_map().end_point(region_scope_span);
+
+                scope.drops.push(DropData {
+                    source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
+                    local,
+                    kind: DropKind::Value,
+                    backwards_incompatible_lint: true,
+                });
+
+                return;
+            }
+        }
+        span_bug!(
+            span,
+            "region scope {:?} not in scope to drop {:?} for linting",
+            region_scope,
+            local
+        );
+    }
+
     /// Indicates that the "local operand" stored in `local` is
     /// *moved* at some point during execution (see `local_scope` for
     /// more information about what a "local operand" is -- in short,
@@ -1378,16 +1430,25 @@ fn build_scope_drops<'tcx>(
                     continue;
                 }
 
-                unwind_drops.add_entry_point(block, unwind_to);
-
-                let next = cfg.start_new_block();
-                cfg.terminate(block, source_info, TerminatorKind::Drop {
-                    place: local.into(),
-                    target: next,
-                    unwind: UnwindAction::Continue,
-                    replace: false,
-                });
-                block = next;
+                if drop_data.backwards_incompatible_lint {
+                    cfg.push(block, Statement {
+                        source_info,
+                        kind: StatementKind::BackwardIncompatibleDropHint {
+                            place: Box::new(local.into()),
+                            reason: BackwardIncompatibleDropReason::Edition2024,
+                        },
+                    });
+                } else {
+                    unwind_drops.add_entry_point(block, unwind_to);
+                    let next = cfg.start_new_block();
+                    cfg.terminate(block, source_info, TerminatorKind::Drop {
+                        place: local.into(),
+                        target: next,
+                        unwind: UnwindAction::Continue,
+                        replace: false,
+                    });
+                    block = next;
+                }
             }
             DropKind::Storage => {
                 if storage_dead_on_unwind {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 4a64a1f0f3e..b497e54d480 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Wild |
                 // these just wrap other patterns, which we recurse on below.
                 PatKind::Or { .. } |
-                PatKind::InlineConstant { .. } |
+                PatKind::ExpandedConstant { .. } |
                 PatKind::AscribeUserType { .. } |
                 PatKind::Error(_) => {}
             }
@@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
             }
-            PatKind::InlineConstant { def, .. } => {
-                self.visit_inner_body(*def);
+            PatKind::ExpandedConstant { def_id, is_inline, .. } => {
+                if let Some(def) = def_id.as_local()
+                    && *is_inline
+                {
+                    self.visit_inner_body(def);
+                }
                 visit::walk_pat(self, pat);
             }
             _ => {
@@ -533,8 +537,45 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     self.requires_unsafe(expr.span, DerefOfRawPointer);
                 }
             }
-            ExprKind::InlineAsm { .. } => {
+            ExprKind::InlineAsm(box InlineAsmExpr {
+                asm_macro: _,
+                ref operands,
+                template: _,
+                options: _,
+                line_spans: _,
+            }) => {
                 self.requires_unsafe(expr.span, UseOfInlineAssembly);
+
+                // For inline asm, do not use `walk_expr`, since we want to handle the label block
+                // specially.
+                for op in &**operands {
+                    use rustc_middle::thir::InlineAsmOperand::*;
+                    match op {
+                        In { expr, reg: _ }
+                        | Out { expr: Some(expr), reg: _, late: _ }
+                        | InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]),
+                        SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
+                            self.visit_expr(&self.thir()[*in_expr]);
+                            if let Some(out_expr) = out_expr {
+                                self.visit_expr(&self.thir()[*out_expr]);
+                            }
+                        }
+                        Out { expr: None, reg: _, late: _ }
+                        | Const { value: _, span: _ }
+                        | SymFn { value: _, span: _ }
+                        | SymStatic { def_id: _ } => {}
+                        Label { block } => {
+                            // Label blocks are safe context.
+                            // `asm!()` is forced to be wrapped inside unsafe. If there's no special
+                            // treatment, the label blocks would also always be unsafe with no way
+                            // of opting out.
+                            self.in_safety_context(SafetyContext::Safe, |this| {
+                                visit::walk_block(this, &this.thir()[*block])
+                            });
+                        }
+                    }
+                }
+                return;
             }
             ExprKind::Adt(box AdtExpr {
                 adt_def,
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 62c6d85b73f..df3a2344c5e 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -593,6 +593,14 @@ pub(crate) struct UnreachablePattern<'tcx> {
     pub(crate) uninhabited_note: Option<()>,
     #[label(mir_build_unreachable_covered_by_catchall)]
     pub(crate) covered_by_catchall: Option<Span>,
+    #[subdiagnostic]
+    pub(crate) wanted_constant: Option<WantedConstant>,
+    #[note(mir_build_unreachable_pattern_const_reexport_accessible)]
+    pub(crate) accessible_constant: Option<Span>,
+    #[note(mir_build_unreachable_pattern_const_inaccessible)]
+    pub(crate) inaccessible_constant: Option<Span>,
+    #[note(mir_build_unreachable_pattern_let_binding)]
+    pub(crate) pattern_let_binding: Option<Span>,
     #[label(mir_build_unreachable_covered_by_one)]
     pub(crate) covered_by_one: Option<Span>,
     #[note(mir_build_unreachable_covered_by_many)]
@@ -602,6 +610,20 @@ pub(crate) struct UnreachablePattern<'tcx> {
     pub(crate) suggest_remove: Option<Span>,
 }
 
+#[derive(Subdiagnostic)]
+#[suggestion(
+    mir_build_unreachable_pattern_wanted_const,
+    code = "{const_path}",
+    applicability = "machine-applicable"
+)]
+pub(crate) struct WantedConstant {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) is_typo: bool,
+    pub(crate) const_name: String,
+    pub(crate) const_path: String,
+}
+
 #[derive(Diagnostic)]
 #[diag(mir_build_const_pattern_depends_on_generic_parameter, code = E0158)]
 pub(crate) struct ConstPatternDependsOnGenericParameter {
@@ -860,8 +882,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     pub(crate) uncovered: Uncovered,
     #[subdiagnostic]
     pub(crate) inform: Option<Inform>,
+    #[label(mir_build_confused)]
+    pub(crate) interpreted_as_const: Option<Span>,
     #[subdiagnostic]
-    pub(crate) interpreted_as_const: Option<InterpretedAsConst>,
+    pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>,
     #[subdiagnostic]
     pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>,
     #[note(mir_build_privately_uninhabited)]
@@ -911,9 +935,9 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
 #[suggestion(
     mir_build_interpreted_as_const,
     code = "{variable}_var",
-    applicability = "maybe-incorrect"
+    applicability = "maybe-incorrect",
+    style = "verbose"
 )]
-#[label(mir_build_confused)]
 pub(crate) struct InterpretedAsConst {
     #[primary_span]
     pub(crate) span: Span,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 198fa4ffb7a..47b7f332951 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -23,7 +23,6 @@ use tracing::{debug, info, instrument, trace};
 
 use crate::errors;
 use crate::thir::cx::Cx;
-use crate::thir::cx::region::Scope;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
 impl<'tcx> Cx<'tcx> {
@@ -240,7 +239,7 @@ impl<'tcx> Cx<'tcx> {
     fn mirror_expr_cast(
         &mut self,
         source: &'tcx hir::Expr<'tcx>,
-        temp_lifetime: Option<Scope>,
+        temp_lifetime: TempLifetime,
         span: Span,
     ) -> ExprKind<'tcx> {
         let tcx = self.tcx;
@@ -325,7 +324,7 @@ impl<'tcx> Cx<'tcx> {
     fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
         let tcx = self.tcx;
         let expr_ty = self.typeck_results().expr_ty(expr);
-        let temp_lifetime =
+        let (temp_lifetime, backwards_incompatible) =
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
 
         let kind = match expr.kind {
@@ -361,7 +360,7 @@ impl<'tcx> Cx<'tcx> {
                     let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e));
                     let tupled_args = Expr {
                         ty: Ty::new_tup_from_iter(tcx, arg_tys),
-                        temp_lifetime,
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                         span: expr.span,
                         kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
                     };
@@ -391,7 +390,10 @@ impl<'tcx> Cx<'tcx> {
                                 && let [value] = args
                             {
                                 return Expr {
-                                    temp_lifetime,
+                                    temp_lifetime: TempLifetime {
+                                        temp_lifetime,
+                                        backwards_incompatible,
+                                    },
                                     ty: expr_ty,
                                     span: expr.span,
                                     kind: ExprKind::Box { value: self.mirror_expr(value) },
@@ -811,13 +813,13 @@ impl<'tcx> Cx<'tcx> {
             },
             hir::ExprKind::Loop(body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_id);
-                let temp_lifetime = self
+                let (temp_lifetime, backwards_incompatible) = self
                     .rvalue_scopes
                     .temporary_scope(self.region_scope_tree, body.hir_id.local_id);
                 let block = self.mirror_block(body);
                 let body = self.thir.exprs.push(Expr {
                     ty: block_ty,
-                    temp_lifetime,
+                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                     span: self.thir[block].span,
                     kind: ExprKind::Block { block },
                 });
@@ -838,13 +840,17 @@ impl<'tcx> Cx<'tcx> {
                     expr, cast_ty.hir_id, user_ty,
                 );
 
-                let cast = self.mirror_expr_cast(source, temp_lifetime, expr.span);
+                let cast = self.mirror_expr_cast(
+                    source,
+                    TempLifetime { temp_lifetime, backwards_incompatible },
+                    expr.span,
+                );
 
                 if let Some(user_ty) = user_ty {
                     // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
                     //       inefficient, revisit this when performance becomes an issue.
                     let cast_expr = self.thir.exprs.push(Expr {
-                        temp_lifetime,
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                         ty: expr_ty,
                         span: expr.span,
                         kind: cast,
@@ -887,7 +893,12 @@ impl<'tcx> Cx<'tcx> {
             hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"),
         };
 
-        Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
+        Expr {
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+            ty: expr_ty,
+            span: expr.span,
+            kind,
+        }
     }
 
     fn user_args_applied_to_res(
@@ -931,7 +942,7 @@ impl<'tcx> Cx<'tcx> {
         span: Span,
         overloaded_callee: Option<Ty<'tcx>>,
     ) -> Expr<'tcx> {
-        let temp_lifetime =
+        let (temp_lifetime, backwards_incompatible) =
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let (ty, user_ty) = match overloaded_callee {
             Some(fn_def) => (fn_def, None),
@@ -952,7 +963,12 @@ impl<'tcx> Cx<'tcx> {
                 )
             }
         };
-        Expr { temp_lifetime, ty, span, kind: ExprKind::ZstLiteral { user_ty } }
+        Expr {
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+            ty,
+            span,
+            kind: ExprKind::ZstLiteral { user_ty },
+        }
     }
 
     fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
@@ -1025,7 +1041,7 @@ impl<'tcx> Cx<'tcx> {
             Res::Def(DefKind::Static { .. }, id) => {
                 // this is &raw for extern static or static mut, and & for other statics
                 let ty = self.tcx.static_ptr_ty(id, self.typing_env());
-                let temp_lifetime = self
+                let (temp_lifetime, backwards_incompatible) = self
                     .rvalue_scopes
                     .temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
                 let kind = if self.tcx.is_thread_local_static(id) {
@@ -1035,7 +1051,12 @@ impl<'tcx> Cx<'tcx> {
                     ExprKind::StaticRef { alloc_id, ty, def_id: id }
                 };
                 ExprKind::Deref {
-                    arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
+                    arg: self.thir.exprs.push(Expr {
+                        ty,
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                        span: expr.span,
+                        kind,
+                    }),
                 }
             }
 
@@ -1106,13 +1127,13 @@ impl<'tcx> Cx<'tcx> {
 
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
-        let temp_lifetime =
+        let (temp_lifetime, backwards_incompatible) =
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let fun = self.method_callee(expr, span, overloaded_callee);
         let fun = self.thir.exprs.push(fun);
         let fun_ty = self.thir[fun].ty;
         let ref_expr = self.thir.exprs.push(Expr {
-            temp_lifetime,
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
             ty: ref_ty,
             span,
             kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span },
@@ -1127,7 +1148,7 @@ impl<'tcx> Cx<'tcx> {
         closure_expr: &'tcx hir::Expr<'tcx>,
         place: HirPlace<'tcx>,
     ) -> Expr<'tcx> {
-        let temp_lifetime = self
+        let (temp_lifetime, backwards_incompatible) = self
             .rvalue_scopes
             .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
@@ -1143,7 +1164,7 @@ impl<'tcx> Cx<'tcx> {
         };
 
         let mut captured_place_expr = Expr {
-            temp_lifetime,
+            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
             ty: var_ty,
             span: closure_expr.span,
             kind: self.convert_var(var_hir_id),
@@ -1168,8 +1189,12 @@ impl<'tcx> Cx<'tcx> {
                 }
             };
 
-            captured_place_expr =
-                Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
+            captured_place_expr = Expr {
+                temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                ty: proj.ty,
+                span: closure_expr.span,
+                kind,
+            };
         }
 
         captured_place_expr
@@ -1184,7 +1209,7 @@ impl<'tcx> Cx<'tcx> {
         let upvar_capture = captured_place.info.capture_kind;
         let captured_place_expr =
             self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
-        let temp_lifetime = self
+        let (temp_lifetime, backwards_incompatible) = self
             .rvalue_scopes
             .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
 
@@ -1201,7 +1226,7 @@ impl<'tcx> Cx<'tcx> {
                     }
                 };
                 Expr {
-                    temp_lifetime,
+                    temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
                     ty: upvar_ty,
                     span: closure_expr.span,
                     kind: ExprKind::Borrow {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 033501c66db..37411561600 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,7 +7,9 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_e
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::Reveal;
+use rustc_lint::Level;
 use rustc_middle::bug;
 use rustc_middle::middle::limits::get_limit_size;
 use rustc_middle::thir::visit::Visitor;
@@ -22,8 +24,10 @@ use rustc_pattern_analysis::rustc::{
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
+use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::{Span, sym};
+use rustc_trait_selection::infer::InferCtxtExt;
 use tracing::instrument;
 
 use crate::errors::*;
@@ -678,8 +682,25 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let mut let_suggestion = None;
         let mut misc_suggestion = None;
         let mut interpreted_as_const = None;
+        let mut interpreted_as_const_sugg = None;
 
-        if let PatKind::Constant { .. }
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. }
+        | PatKind::AscribeUserType {
+            subpattern:
+                box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. },
+            ..
+        } = pat.kind
+            && let DefKind::Const = self.tcx.def_kind(def_id)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
+        {
+            let span = self.tcx.def_span(def_id);
+            let variable = self.tcx.item_name(def_id).to_string();
+            // When we encounter a constant as the binding name, point at the `const` definition.
+            interpreted_as_const = Some(span);
+            interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable });
+        } else if let PatKind::Constant { .. }
         | PatKind::AscribeUserType {
             subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
             ..
@@ -692,9 +713,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral {
                     start_span: pat.span.shrink_to_lo(),
                 });
-            } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
-                interpreted_as_const =
-                    Some(InterpretedAsConst { span: pat.span, variable: snippet });
             }
         }
 
@@ -743,6 +761,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             uncovered: Uncovered::new(pat.span, &cx, witnesses),
             inform,
             interpreted_as_const,
+            interpreted_as_const_sugg,
             witness_1_is_privately_uninhabited,
             _p: (),
             pattern_ty,
@@ -954,6 +973,10 @@ fn report_unreachable_pattern<'p, 'tcx>(
         covered_by_one: None,
         covered_by_many: None,
         covered_by_many_n_more_count: 0,
+        wanted_constant: None,
+        accessible_constant: None,
+        inaccessible_constant: None,
+        pattern_let_binding: None,
         suggest_remove: None,
     };
     match explanation.covered_by.as_slice() {
@@ -976,7 +999,10 @@ fn report_unreachable_pattern<'p, 'tcx>(
             });
         }
         [covering_pat] if pat_is_catchall(covering_pat) => {
-            lint.covered_by_catchall = Some(covering_pat.data().span);
+            // A binding pattern that matches all, a single binding name.
+            let pat = covering_pat.data();
+            lint.covered_by_catchall = Some(pat.span);
+            find_fallback_pattern_typo(cx, hir_id, pat, &mut lint);
         }
         [covering_pat] => {
             lint.covered_by_one = Some(covering_pat.data().span);
@@ -1009,6 +1035,157 @@ fn report_unreachable_pattern<'p, 'tcx>(
     cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint);
 }
 
+/// Detect typos that were meant to be a `const` but were interpreted as a new pattern binding.
+fn find_fallback_pattern_typo<'tcx>(
+    cx: &PatCtxt<'_, 'tcx>,
+    hir_id: HirId,
+    pat: &Pat<'tcx>,
+    lint: &mut UnreachablePattern<'_>,
+) {
+    if let (Level::Allow, _) = cx.tcx.lint_level_at_node(UNREACHABLE_PATTERNS, hir_id) {
+        // This is because we use `with_no_trimmed_paths` later, so if we never emit the lint we'd
+        // ICE. At the same time, we don't really need to do all of this if we won't emit anything.
+        return;
+    }
+    if let PatKind::Binding { name, subpattern: None, ty, .. } = pat.kind {
+        // See if the binding might have been a `const` that was mistyped or out of scope.
+        let mut accessible = vec![];
+        let mut accessible_path = vec![];
+        let mut inaccessible = vec![];
+        let mut imported = vec![];
+        let mut imported_spans = vec![];
+        let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::non_body_analysis());
+        let parent = cx.tcx.hir().get_parent_item(hir_id);
+
+        for item in cx.tcx.hir_crate_items(()).free_items() {
+            if let DefKind::Use = cx.tcx.def_kind(item.owner_id) {
+                // Look for consts being re-exported.
+                let item = cx.tcx.hir().expect_item(item.owner_id.def_id);
+                let use_name = item.ident.name;
+                let hir::ItemKind::Use(path, _) = item.kind else {
+                    continue;
+                };
+                for res in &path.res {
+                    if let Res::Def(DefKind::Const, id) = res
+                        && infcx.can_eq(cx.param_env, ty, cx.tcx.type_of(id).instantiate_identity())
+                    {
+                        if cx.tcx.visibility(id).is_accessible_from(parent, cx.tcx) {
+                            // The original const is accessible, suggest using it directly.
+                            let item_name = cx.tcx.item_name(*id);
+                            accessible.push(item_name);
+                            accessible_path.push(with_no_trimmed_paths!(cx.tcx.def_path_str(id)));
+                        } else if cx
+                            .tcx
+                            .visibility(item.owner_id)
+                            .is_accessible_from(parent, cx.tcx)
+                        {
+                            // The const is accessible only through the re-export, point at
+                            // the `use`.
+                            imported.push(use_name);
+                            imported_spans.push(item.ident.span);
+                        }
+                    }
+                }
+            }
+            if let DefKind::Const = cx.tcx.def_kind(item.owner_id)
+                && infcx.can_eq(
+                    cx.param_env,
+                    ty,
+                    cx.tcx.type_of(item.owner_id).instantiate_identity(),
+                )
+            {
+                // Look for local consts.
+                let item_name = cx.tcx.item_name(item.owner_id.into());
+                let vis = cx.tcx.visibility(item.owner_id);
+                if vis.is_accessible_from(parent, cx.tcx) {
+                    accessible.push(item_name);
+                    let path = if item_name == name {
+                        // We know that the const wasn't in scope because it has the exact
+                        // same name, so we suggest the full path.
+                        with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id))
+                    } else {
+                        // The const is likely just typoed, and nothing else.
+                        cx.tcx.def_path_str(item.owner_id)
+                    };
+                    accessible_path.push(path);
+                } else if name == item_name {
+                    // The const exists somewhere in this crate, but it can't be imported
+                    // from this pattern's scope. We'll just point at its definition.
+                    inaccessible.push(cx.tcx.def_span(item.owner_id));
+                }
+            }
+        }
+        if let Some((i, &const_name)) =
+            accessible.iter().enumerate().find(|(_, &const_name)| const_name == name)
+        {
+            // The pattern name is an exact match, so the pattern needed to be imported.
+            lint.wanted_constant = Some(WantedConstant {
+                span: pat.span,
+                is_typo: false,
+                const_name: const_name.to_string(),
+                const_path: accessible_path[i].clone(),
+            });
+        } else if let Some(name) = find_best_match_for_name(&accessible, name, None) {
+            // The pattern name is likely a typo.
+            lint.wanted_constant = Some(WantedConstant {
+                span: pat.span,
+                is_typo: true,
+                const_name: name.to_string(),
+                const_path: name.to_string(),
+            });
+        } else if let Some(i) =
+            imported.iter().enumerate().find(|(_, &const_name)| const_name == name).map(|(i, _)| i)
+        {
+            // The const with the exact name wasn't re-exported from an import in this
+            // crate, we point at the import.
+            lint.accessible_constant = Some(imported_spans[i]);
+        } else if let Some(name) = find_best_match_for_name(&imported, name, None) {
+            // The typoed const wasn't re-exported by an import in this crate, we suggest
+            // the right name (which will likely require another follow up suggestion).
+            lint.wanted_constant = Some(WantedConstant {
+                span: pat.span,
+                is_typo: true,
+                const_path: name.to_string(),
+                const_name: name.to_string(),
+            });
+        } else if !inaccessible.is_empty() {
+            for span in inaccessible {
+                // The const with the exact name match isn't accessible, we just point at it.
+                lint.inaccessible_constant = Some(span);
+            }
+        } else {
+            // Look for local bindings for people that might have gotten confused with how
+            // `let` and `const` works.
+            for (_, node) in cx.tcx.hir().parent_iter(hir_id) {
+                match node {
+                    hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(let_stmt), .. }) => {
+                        if let hir::PatKind::Binding(_, _, binding_name, _) = let_stmt.pat.kind {
+                            if name == binding_name.name {
+                                lint.pattern_let_binding = Some(binding_name.span);
+                            }
+                        }
+                    }
+                    hir::Node::Block(hir::Block { stmts, .. }) => {
+                        for stmt in *stmts {
+                            if let hir::StmtKind::Let(let_stmt) = stmt.kind {
+                                if let hir::PatKind::Binding(_, _, binding_name, _) =
+                                    let_stmt.pat.kind
+                                {
+                                    if name == binding_name.name {
+                                        lint.pattern_let_binding = Some(binding_name.span);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    hir::Node::Item(_) => break,
+                    _ => {}
+                }
+            }
+        }
+    }
+}
+
 /// Report unreachable arms, if any.
 fn report_arm_reachability<'p, 'tcx>(
     cx: &PatCtxt<'p, 'tcx>,
@@ -1112,13 +1289,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
             if ty.is_ptr_sized_integral() {
                 if ty.inner() == cx.tcx.types.usize {
                     err.note(format!(
-                        "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have a fixed maximum value, so half-open ranges are \
+                         necessary to match exhaustively",
                     ));
                 } else if ty.inner() == cx.tcx.types.isize {
                     err.note(format!(
-                        "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have fixed minimum and maximum values, so half-open \
+                         ranges are necessary to match exhaustively",
                     ));
                 }
             } else if ty.inner() == cx.tcx.types.str_ {
@@ -1139,6 +1316,31 @@ fn report_non_exhaustive_match<'p, 'tcx>(
         }
     }
 
+    for &arm in arms {
+        let arm = &thir.arms[arm];
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind
+            && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
+        {
+            let const_name = cx.tcx.item_name(def_id);
+            err.span_label(
+                arm.pattern.span,
+                format!(
+                    "this pattern doesn't introduce a new catch-all binding, but rather pattern \
+                     matches against the value of constant `{const_name}`",
+                ),
+            );
+            err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here"));
+            err.span_suggestion_verbose(
+                arm.pattern.span.shrink_to_hi(),
+                "if you meant to introduce a binding, use a different name",
+                "_var".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     // Whether we suggest the actual missing patterns or `_`.
     let suggest_the_witnesses = witnesses.len() < 4;
     let suggested_arm = if suggest_the_witnesses {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 6b9e3b85999..08c6b4abd3b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -149,21 +149,30 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             None => Ok((None, None, None)),
             Some(expr) => {
                 let (kind, ascr, inline_const) = match self.lower_lit(expr) {
-                    PatKind::InlineConstant { subpattern, def } => {
-                        (subpattern.kind, None, Some(def))
+                    PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
+                        (subpattern.kind, None, def_id.as_local())
+                    }
+                    PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
+                        (subpattern.kind, None, None)
                     }
                     PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
                         (kind, Some(ascription), None)
                     }
                     kind => (kind, None, None),
                 };
-                let value = if let PatKind::Constant { value } = kind {
-                    value
-                } else {
-                    let msg = format!(
-                        "found bad range pattern endpoint `{expr:?}` outside of error recovery"
-                    );
-                    return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                let value = match kind {
+                    PatKind::Constant { value } => value,
+                    PatKind::ExpandedConstant { subpattern, .. }
+                        if let PatKind::Constant { value } = subpattern.kind =>
+                    {
+                        value
+                    }
+                    _ => {
+                        let msg = format!(
+                            "found bad range pattern endpoint `{expr:?}` outside of error recovery"
+                        );
+                        return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                    }
                 };
                 Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
             }
@@ -288,7 +297,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             };
         }
         for def in [lo_inline, hi_inline].into_iter().flatten() {
-            kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
+            kind = PatKind::ExpandedConstant {
+                def_id: def.to_def_id(),
+                is_inline: true,
+                subpattern: Box::new(Pat { span, ty, kind }),
+            };
         }
         Ok(kind)
     }
@@ -562,7 +575,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let args = self.typeck_results.node_args(id);
         let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
-        let pattern = self.const_to_pat(c, ty, id, span);
+        let subpattern = self.const_to_pat(c, ty, id, span);
+        let pattern = Box::new(Pat {
+            span,
+            ty,
+            kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
+        });
 
         if !is_associated_const {
             return pattern;
@@ -637,7 +655,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
         let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
-        PatKind::InlineConstant { subpattern, def: def_id }
+        PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
     }
 
     /// Converts literals, paths and negation of literals to patterns.
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index dae13df4054..6be0ed5fb31 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -707,9 +707,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::InlineConstant { def, subpattern } => {
-                print_indented!(self, "InlineConstant {", depth_lvl + 1);
-                print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
+            PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
+                print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
+                print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
+                print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2);
                 print_indented!(self, "subpattern:", depth_lvl + 2);
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index e06c1f2bb49..fd7254a0210 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -253,6 +253,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => None,
         };
         if let Some(destination) = destination {
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index c5fd2a631ff..576289e228a 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -157,6 +157,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
             | StatementKind::Nop
             | StatementKind::Retag(..)
             | StatementKind::Intrinsic(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::StorageLive(..) => {}
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index fd8e403ebc2..0880364bfca 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -385,6 +385,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index 9bbfae17fd9..d00bfc66a6a 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -25,6 +25,31 @@ mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspen
     .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
 mir_transform_operation_will_panic = this operation will panic at runtime
 
+mir_transform_tail_expr_drop_order = relative drop order changing in Rust 2024
+    .temporaries = in Rust 2024, this temporary value will be dropped first
+    .observers = in Rust 2024, this local variable or temporary value will be dropped second
+    .note_dtors =
+        dropping the temporary value runs this custom `Drop` impl, which we could not prove to be side-effect free
+    .note_observer_dtors =
+        dropping the local runs this custom `Drop` impl, which we could not prove to be side-effect free
+    .drop_location =
+        now the temporary value is dropped here, before the local variables in the block or statement
+    .note_epilogue = most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+    .label_local_epilogue = {$is_dropped_first_edition_2024 ->
+        [true] up until Edition 2021 `{$name}` is dropped last but will be dropped earlier in Edition 2024
+        *[false] `{$name}` will be dropped later as of Edition 2024
+    }
+
+mir_transform_tail_expr_dtor = {$dtor_kind ->
+    [dyn] `{$name}` may invoke a custom destructor because it contains a trait object
+    *[concrete] `{$name}` invokes this custom destructor
+    }
+
+mir_transform_tail_expr_local = {$is_generated_name ->
+        [true] this value will be stored in a temporary; let us call it `{$name}`
+        *[false] `{$name}` calls a custom destructor
+    }
+
 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)
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index d38a1dd11dc..8295a806d71 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1772,6 +1772,7 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> {
             | StatementKind::Coverage(..)
             | StatementKind::Intrinsic(..)
             | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 875db23ce09..824d657e1fc 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -97,6 +97,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
         | StatementKind::ConstEvalCounter
+        | StatementKind::BackwardIncompatibleDropHint { .. }
         | StatementKind::Nop => None,
 
         // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 26480be29f3..d017202f48b 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -186,7 +186,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             | StatementKind::FakeRead(..)
             | StatementKind::PlaceMention(..)
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..) => (),
+            | StatementKind::BackwardIncompatibleDropHint { .. }
+            | StatementKind::AscribeUserType(..) => {}
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 2898f82e25c..0c75cdadc92 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -99,7 +99,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 | StatementKind::Intrinsic(_)
                 | StatementKind::ConstEvalCounter
                 | StatementKind::PlaceMention(_)
-                | StatementKind::Nop => (),
+                | StatementKind::BackwardIncompatibleDropHint { .. }
+                | StatementKind::Nop => {}
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
                     bug!("{:?} not found in this MIR phase!", statement.kind)
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index beeab0d4a66..9c74b2f0839 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -581,7 +581,7 @@ impl WriteInfo {
                     | Rvalue::RawPtr(_, _)
                     | Rvalue::Len(_)
                     | Rvalue::Discriminant(_)
-                    | Rvalue::CopyForDeref(_) => (),
+                    | Rvalue::CopyForDeref(_) => {}
                 }
             }
             // Retags are technically also reads, but reporting them as a write suffices
@@ -596,7 +596,8 @@ impl WriteInfo {
             | StatementKind::Coverage(_)
             | StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
-            | StatementKind::PlaceMention(_) => (),
+            | StatementKind::BackwardIncompatibleDropHint { .. }
+            | StatementKind::PlaceMention(_) => {}
             StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
                 bug!("{:?} not found in this MIR phase", statement)
             }
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index b3d9af37204..976f4a8e919 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -100,7 +100,7 @@ use rustc_middle::bug;
 use rustc_middle::mir::interpret::GlobalAlloc;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::DefId;
@@ -294,7 +294,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     }
 
     fn typing_env(&self) -> ty::TypingEnv<'tcx> {
-        self.ecx.typing_env
+        self.ecx.typing_env()
     }
 
     #[instrument(level = "trace", skip(self), ret)]
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 5c2c36db0f7..beed007589b 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -352,6 +352,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
             | StatementKind::FakeRead(..)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => None,
         }
     }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 5651bf469d5..bfb842e4485 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -50,6 +50,7 @@ mod deduce_param_attrs;
 mod errors;
 mod ffi_unwind_calls;
 mod lint;
+mod lint_tail_expr_drop_order;
 mod shim;
 mod ssa;
 
@@ -490,6 +491,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
     }
 
     let (body, _) = tcx.mir_promoted(def);
+    lint_tail_expr_drop_order::run_lint(tcx, def, &body.borrow());
     let mut body = body.steal();
 
     if let Some(error_reported) = tainted_by_errors {
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
new file mode 100644
index 00000000000..b8502fcbafb
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -0,0 +1,701 @@
+use std::cell::RefCell;
+use std::collections::hash_map;
+use std::rc::Rc;
+
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::unord::{UnordMap, UnordSet};
+use rustc_errors::Subdiagnostic;
+use rustc_hir::CRATE_HIR_ID;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_index::bit_set::ChunkedBitSet;
+use rustc_index::{IndexSlice, IndexVec};
+use rustc_macros::{LintDiagnostic, Subdiagnostic};
+use rustc_middle::bug;
+use rustc_middle::mir::{
+    self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind,
+    dump_mir,
+};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
+use rustc_mir_dataflow::{Analysis, MaybeReachable, ResultsCursor};
+use rustc_session::lint::builtin::TAIL_EXPR_DROP_ORDER;
+use rustc_session::lint::{self};
+use rustc_span::{DUMMY_SP, Span, Symbol};
+use rustc_type_ir::data_structures::IndexMap;
+use smallvec::{SmallVec, smallvec};
+use tracing::{debug, instrument};
+
+fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool {
+    left.local == right.local
+        && left.projection.iter().zip(right.projection).all(|(left, right)| left == right)
+}
+
+/// Cache entry of `drop` at a `BasicBlock`
+#[derive(Debug, Clone, Copy)]
+enum MovePathIndexAtBlock {
+    /// We know nothing yet
+    Unknown,
+    /// We know that the `drop` here has no effect
+    None,
+    /// We know that the `drop` here will invoke a destructor
+    Some(MovePathIndex),
+}
+
+struct DropsReachable<'a, 'mir, 'tcx> {
+    body: &'a Body<'tcx>,
+    place: &'a Place<'tcx>,
+    drop_span: &'a mut Option<Span>,
+    move_data: &'a MoveData<'tcx>,
+    maybe_init: &'a mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
+    block_drop_value_info: &'a mut IndexSlice<BasicBlock, MovePathIndexAtBlock>,
+    collected_drops: &'a mut ChunkedBitSet<MovePathIndex>,
+    visited: FxHashMap<BasicBlock, Rc<RefCell<ChunkedBitSet<MovePathIndex>>>>,
+}
+
+impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> {
+    fn visit(&mut self, block: BasicBlock) {
+        let move_set_size = self.move_data.move_paths.len();
+        let make_new_path_set = || Rc::new(RefCell::new(ChunkedBitSet::new_empty(move_set_size)));
+
+        let data = &self.body.basic_blocks[block];
+        let Some(terminator) = &data.terminator else { return };
+        // Given that we observe these dropped locals here at `block` so far,
+        // we will try to update the successor blocks.
+        // An occupied entry at `block` in `self.visited` signals that we have visited `block` before.
+        let dropped_local_here =
+            Rc::clone(self.visited.entry(block).or_insert_with(make_new_path_set));
+        // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately it is expensive.
+        // Let's cache them in `self.block_drop_value_info`.
+        match self.block_drop_value_info[block] {
+            MovePathIndexAtBlock::Some(dropped) => {
+                dropped_local_here.borrow_mut().insert(dropped);
+            }
+            MovePathIndexAtBlock::Unknown => {
+                if let TerminatorKind::Drop { place, .. } = &terminator.kind
+                    && let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) =
+                        self.move_data.rev_lookup.find(place.as_ref())
+                {
+                    // Since we are working with MIRs at a very early stage,
+                    // observing a `drop` terminator is not indicative enough that
+                    // the drop will definitely happen.
+                    // That is decided in the drop elaboration pass instead.
+                    // Therefore, we need to consult with the maybe-initialization information.
+                    self.maybe_init.seek_before_primary_effect(Location {
+                        block,
+                        statement_index: data.statements.len(),
+                    });
+
+                    // Check if the drop of `place` under inspection is really in effect.
+                    // This is true only when `place` may have been initialized along a control flow path from a BID to the drop program point today.
+                    // In other words, this is where the drop of `place` will happen in the future instead.
+                    if let MaybeReachable::Reachable(maybe_init) = self.maybe_init.get()
+                        && maybe_init.contains(idx)
+                    {
+                        // We also cache the drop information, so that we do not need to check on data-flow cursor again
+                        self.block_drop_value_info[block] = MovePathIndexAtBlock::Some(idx);
+                        dropped_local_here.borrow_mut().insert(idx);
+                    } else {
+                        self.block_drop_value_info[block] = MovePathIndexAtBlock::None;
+                    }
+                }
+            }
+            MovePathIndexAtBlock::None => {}
+        }
+
+        for succ in terminator.successors() {
+            let target = &self.body.basic_blocks[succ];
+            if target.is_cleanup {
+                continue;
+            }
+
+            // As long as we are passing through a new block, or new dropped places to propagate,
+            // we will proceed with `succ`
+            let dropped_local_there = match self.visited.entry(succ) {
+                hash_map::Entry::Occupied(occupied_entry) => {
+                    if succ == block
+                        || !occupied_entry.get().borrow_mut().union(&*dropped_local_here.borrow())
+                    {
+                        // `succ` has been visited but no new drops observed so far,
+                        // so we can bail on `succ` until new drop information arrives
+                        continue;
+                    }
+                    Rc::clone(occupied_entry.get())
+                }
+                hash_map::Entry::Vacant(vacant_entry) => Rc::clone(
+                    vacant_entry.insert(Rc::new(RefCell::new(dropped_local_here.borrow().clone()))),
+                ),
+            };
+            if let Some(terminator) = &target.terminator
+                && let TerminatorKind::Drop {
+                    place: dropped_place,
+                    target: _,
+                    unwind: _,
+                    replace: _,
+                } = &terminator.kind
+                && place_has_common_prefix(dropped_place, self.place)
+            {
+                // We have now reached the current drop of the `place`.
+                // Let's check the observed dropped places in.
+                self.collected_drops.union(&*dropped_local_there.borrow());
+                if self.drop_span.is_none() {
+                    // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are still a bit wonky.
+                    // There is a high chance that this span still points to a block rather than a statement semicolon.
+                    *self.drop_span = Some(terminator.source_info.span);
+                }
+                // Now we have discovered a simple control flow path from a future drop point
+                // to the current drop point.
+                // We will not continue from there.
+            } else {
+                self.visit(succ)
+            }
+        }
+    }
+}
+
+/// An additional filter to exclude well-known types from the ecosystem
+/// because their drops are trivial.
+/// This returns additional types to check if the drops are delegated to those.
+/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`.
+fn true_significant_drop_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
+    if let ty::Adt(def, args) = ty.kind() {
+        let mut did = def.did();
+        let mut name_rev = vec![];
+        loop {
+            let key = tcx.def_key(did);
+
+            match key.disambiguated_data.data {
+                rustc_hir::definitions::DefPathData::CrateRoot => {
+                    name_rev.push(tcx.crate_name(did.krate))
+                }
+                rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol),
+                _ => return None,
+            }
+            if let Some(parent) = key.parent {
+                did = DefId { krate: did.krate, index: parent };
+            } else {
+                break;
+            }
+        }
+        let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
+        debug!(?name_str);
+        match name_str[..] {
+            // These are the types from Rust core ecosystem
+            ["sym" | "proc_macro2", ..]
+            | ["core" | "std", "task", "LocalWaker" | "Waker"]
+            | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]),
+            // These are important types from Rust ecosystem
+            ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]),
+            ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
+                if let [ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            ["hashbrown", "raw", "RawDrain"] => {
+                if let [_, ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+/// Returns the list of types with a "potentially sigificant" that may be dropped
+/// by dropping a value of type `ty`.
+#[instrument(level = "debug", skip(tcx, param_env))]
+fn extract_component_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    ty_seen: &mut UnordSet<Ty<'tcx>>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    // Droppiness does not depend on regions, so let us erase them.
+    let ty = tcx
+        .try_normalize_erasing_regions(
+            ty::TypingEnv { param_env, typing_mode: ty::TypingMode::PostAnalysis },
+            ty,
+        )
+        .unwrap_or(ty);
+
+    let tys = tcx.list_significant_drop_tys(param_env.and(ty));
+    debug!(?ty, "components");
+    let mut out_tys = smallvec![];
+    for ty in tys {
+        if let Some(tys) = true_significant_drop_ty(tcx, ty) {
+            // Some types can be further opened up because the drop is simply delegated
+            for ty in tys {
+                if ty_seen.insert(ty) {
+                    out_tys.extend(extract_component_raw(tcx, param_env, ty, ty_seen));
+                }
+            }
+        } else {
+            if ty_seen.insert(ty) {
+                out_tys.push(ty);
+            }
+        }
+    }
+    out_tys
+}
+
+#[instrument(level = "debug", skip(tcx, param_env))]
+fn extract_component_with_significant_dtor<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    let mut tys = extract_component_raw(tcx, param_env, ty, &mut Default::default());
+    let mut deduplicate = FxHashSet::default();
+    tys.retain(|oty| deduplicate.insert(*oty));
+    tys.into_iter().collect()
+}
+
+/// Extract the span of the custom destructor of a type
+/// especially the span of the `impl Drop` header or its entire block
+/// when we are working with current local crate.
+#[instrument(level = "debug", skip(tcx))]
+fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
+    match ty.kind() {
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Error(_)
+        | ty::Str
+        | ty::Never
+        | ty::RawPtr(_, _)
+        | ty::Ref(_, _, _)
+        | ty::FnPtr(_, _)
+        | ty::Tuple(_)
+        | ty::Dynamic(_, _, _)
+        | ty::Alias(_, _)
+        | ty::Bound(_, _)
+        | ty::Pat(_, _)
+        | ty::Placeholder(_)
+        | ty::Infer(_)
+        | ty::Slice(_)
+        | ty::Array(_, _) => None,
+        ty::Adt(adt_def, _) => {
+            let did = adt_def.did();
+            let try_local_did_span = |did: DefId| {
+                if let Some(local) = did.as_local() {
+                    tcx.source_span(local)
+                } else {
+                    tcx.def_span(did)
+                }
+            };
+            let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
+                dtor.did
+            } else if let Some(dtor) = tcx.adt_async_destructor(did) {
+                dtor.future
+            } else {
+                return Some(try_local_did_span(did));
+            };
+            let def_key = tcx.def_key(dtor);
+            let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
+            let parent_did = DefId { index: parent_index, krate: dtor.krate };
+            Some(try_local_did_span(parent_did))
+        }
+        ty::Coroutine(did, _)
+        | ty::CoroutineWitness(did, _)
+        | ty::CoroutineClosure(did, _)
+        | ty::Closure(did, _)
+        | ty::FnDef(did, _)
+        | ty::Foreign(did) => Some(tcx.def_span(did)),
+        ty::Param(_) => None,
+    }
+}
+
+/// Check if a moved place at `idx` is a part of a BID.
+/// The use of this check is that we will consider drops on these
+/// as a drop of the overall BID and, thus, we can exclude it from the diagnosis.
+fn place_descendent_of_bids<'tcx>(
+    mut idx: MovePathIndex,
+    move_data: &MoveData<'tcx>,
+    bids: &UnordSet<&Place<'tcx>>,
+) -> bool {
+    loop {
+        let path = &move_data.move_paths[idx];
+        if bids.contains(&path.place) {
+            return true;
+        }
+        if let Some(parent) = path.parent {
+            idx = parent;
+        } else {
+            return false;
+        }
+    }
+}
+
+/// The core of the lint `tail-expr-drop-order`
+pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) {
+    if matches!(tcx.def_kind(def_id), rustc_hir::def::DefKind::SyntheticCoroutineBody) {
+        // A synthetic coroutine has no HIR body and it is enough to just analyse the original body
+        return;
+    }
+    if body.span.edition().at_least_rust_2024()
+        || tcx.lints_that_dont_need_to_run(()).contains(&lint::LintId::of(TAIL_EXPR_DROP_ORDER))
+    {
+        return;
+    }
+    // ## About BIDs in blocks ##
+    // Track the set of blocks that contain a backwards-incompatible drop (BID)
+    // and, for each block, the vector of locations.
+    //
+    // We group them per-block because they tend to scheduled in the same drop ladder block.
+    let mut bid_per_block = IndexMap::default();
+    let mut bid_places = UnordSet::new();
+    let param_env = tcx.param_env(def_id).with_reveal_all_normalized(tcx);
+    let mut ty_dropped_components = UnordMap::default();
+    for (block, data) in body.basic_blocks.iter_enumerated() {
+        for (statement_index, stmt) in data.statements.iter().enumerate() {
+            if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = &stmt.kind {
+                let ty = place.ty(body, tcx).ty;
+                if ty_dropped_components
+                    .entry(ty)
+                    .or_insert_with(|| extract_component_with_significant_dtor(tcx, param_env, ty))
+                    .is_empty()
+                {
+                    continue;
+                }
+                bid_per_block
+                    .entry(block)
+                    .or_insert(vec![])
+                    .push((Location { block, statement_index }, &**place));
+                bid_places.insert(&**place);
+            }
+        }
+    }
+    if bid_per_block.is_empty() {
+        return;
+    }
+
+    dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, |_, _| Ok(()));
+    let locals_with_user_names = collect_user_names(body);
+    let is_closure_like = tcx.is_closure_like(def_id.to_def_id());
+
+    // Compute the "maybe initialized" information for this body.
+    // When we encounter a DROP of some place P we only care
+    // about the drop if `P` may be initialized.
+    let move_data = MoveData::gather_moves(body, tcx, |_| true);
+    let maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data);
+    let mut maybe_init = maybe_init.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body);
+    let mut block_drop_value_info =
+        IndexVec::from_elem_n(MovePathIndexAtBlock::Unknown, body.basic_blocks.len());
+    for (&block, candidates) in &bid_per_block {
+        // We will collect drops on locals on paths between BID points to their actual drop locations
+        // into `all_locals_dropped`.
+        let mut all_locals_dropped = ChunkedBitSet::new_empty(move_data.move_paths.len());
+        let mut drop_span = None;
+        for &(_, place) in candidates.iter() {
+            let mut collected_drops = ChunkedBitSet::new_empty(move_data.move_paths.len());
+            // ## On detecting change in relative drop order ##
+            // Iterate through each BID-containing block `block`.
+            // If the place `P` targeted by the BID is "maybe initialized",
+            // then search forward to find the actual `DROP(P)` point.
+            // Everything dropped between the BID and the actual drop point
+            // is something whose relative drop order will change.
+            DropsReachable {
+                body,
+                place,
+                drop_span: &mut drop_span,
+                move_data: &move_data,
+                maybe_init: &mut maybe_init,
+                block_drop_value_info: &mut block_drop_value_info,
+                collected_drops: &mut collected_drops,
+                visited: Default::default(),
+            }
+            .visit(block);
+            // Compute the set `all_locals_dropped` of local variables that are dropped
+            // after the BID point but before the current drop point.
+            //
+            // These are the variables whose drop impls will be reordered with respect
+            // to `place`.
+            all_locals_dropped.union(&collected_drops);
+        }
+
+        // We shall now exclude some local bindings for the following cases.
+        {
+            let mut to_exclude = ChunkedBitSet::new_empty(all_locals_dropped.domain_size());
+            // We will now do subtraction from the candidate dropped locals, because of the following reasons.
+            for path_idx in all_locals_dropped.iter() {
+                let move_path = &move_data.move_paths[path_idx];
+                let dropped_local = move_path.place.local;
+                // a) A return value _0 will eventually be used
+                // Example:
+                // fn f() -> Droppy {
+                //     let _x = Droppy;
+                //     Droppy
+                // }
+                // _0 holds the literal `Droppy` and rightfully `_x` has to be dropped first
+                if dropped_local == Local::ZERO {
+                    debug!(?dropped_local, "skip return value");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+                // b) If we are analysing a closure, the captures are still dropped last.
+                // This is part of the closure capture lifetime contract.
+                // They are similar to the return value _0 with respect to lifetime rules.
+                if is_closure_like && matches!(dropped_local, ty::CAPTURE_STRUCT_LOCAL) {
+                    debug!(?dropped_local, "skip closure captures");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+                // c) Sometimes we collect places that are projections into the BID locals,
+                // so they are considered dropped now.
+                // Example:
+                // struct NotVeryDroppy(Droppy);
+                // impl Drop for Droppy {..}
+                // fn f() -> NotVeryDroppy {
+                //    let x = NotVeryDroppy(droppy());
+                //    {
+                //        let y: Droppy = x.0;
+                //        NotVeryDroppy(y)
+                //    }
+                // }
+                // `y` takes `x.0`, which invalidates `x` as a complete `NotVeryDroppy`
+                // so there is no point in linting against `x` any more.
+                if place_descendent_of_bids(path_idx, &move_data, &bid_places) {
+                    debug!(?dropped_local, "skip descendent of bids");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+                let observer_ty = move_path.place.ty(body, tcx).ty;
+                // d) The collected local has no custom destructor that passes our ecosystem filter.
+                if ty_dropped_components
+                    .entry(observer_ty)
+                    .or_insert_with(|| {
+                        extract_component_with_significant_dtor(tcx, param_env, observer_ty)
+                    })
+                    .is_empty()
+                {
+                    debug!(?dropped_local, "skip non-droppy types");
+                    to_exclude.insert(path_idx);
+                    continue;
+                }
+            }
+            // Suppose that all BIDs point into the same local,
+            // we can remove the this local from the observed drops,
+            // so that we can focus our diagnosis more on the others.
+            if candidates.iter().all(|&(_, place)| candidates[0].1.local == place.local) {
+                for path_idx in all_locals_dropped.iter() {
+                    if move_data.move_paths[path_idx].place.local == candidates[0].1.local {
+                        to_exclude.insert(path_idx);
+                    }
+                }
+            }
+            all_locals_dropped.subtract(&to_exclude);
+        }
+        if all_locals_dropped.is_empty() {
+            // No drop effect is observable, so let us move on.
+            continue;
+        }
+
+        // ## The final work to assemble the diagnosis ##
+        // First collect or generate fresh names for local variable bindings and temporary values.
+        let local_names = assign_observables_names(
+            all_locals_dropped
+                .iter()
+                .map(|path_idx| move_data.move_paths[path_idx].place.local)
+                .chain(candidates.iter().map(|(_, place)| place.local)),
+            &locals_with_user_names,
+        );
+
+        let mut lint_root = None;
+        let mut local_labels = vec![];
+        // We now collect the types with custom destructors.
+        for &(_, place) in candidates {
+            let linted_local_decl = &body.local_decls[place.local];
+            let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else {
+                bug!("a name should have been assigned")
+            };
+            let name = name.as_str();
+
+            if lint_root.is_none()
+                && let ClearCrossCrate::Set(data) =
+                    &body.source_scopes[linted_local_decl.source_info.scope].local_data
+            {
+                lint_root = Some(data.lint_root);
+            }
+
+            // Collect spans of the custom destructors.
+            let mut seen_dyn = false;
+            let destructors = ty_dropped_components
+                .get(&linted_local_decl.ty)
+                .unwrap()
+                .iter()
+                .filter_map(|&ty| {
+                    if let Some(span) = ty_dtor_span(tcx, ty) {
+                        Some(DestructorLabel { span, name, dtor_kind: "concrete" })
+                    } else if matches!(ty.kind(), ty::Dynamic(..)) {
+                        if seen_dyn {
+                            None
+                        } else {
+                            seen_dyn = true;
+                            Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" })
+                        }
+                    } else {
+                        None
+                    }
+                })
+                .collect();
+            local_labels.push(LocalLabel {
+                span: linted_local_decl.source_info.span,
+                destructors,
+                name,
+                is_generated_name,
+                is_dropped_first_edition_2024: true,
+            });
+        }
+
+        // Similarly, custom destructors of the observed drops.
+        for path_idx in all_locals_dropped.iter() {
+            let place = &move_data.move_paths[path_idx].place;
+            // We are not using the type of the local because the drop may be partial.
+            let observer_ty = place.ty(body, tcx).ty;
+
+            let observer_local_decl = &body.local_decls[place.local];
+            let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else {
+                bug!("a name should have been assigned")
+            };
+            let name = name.as_str();
+
+            let mut seen_dyn = false;
+            let destructors = extract_component_with_significant_dtor(tcx, param_env, observer_ty)
+                .into_iter()
+                .filter_map(|ty| {
+                    if let Some(span) = ty_dtor_span(tcx, ty) {
+                        Some(DestructorLabel { span, name, dtor_kind: "concrete" })
+                    } else if matches!(ty.kind(), ty::Dynamic(..)) {
+                        if seen_dyn {
+                            None
+                        } else {
+                            seen_dyn = true;
+                            Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" })
+                        }
+                    } else {
+                        None
+                    }
+                })
+                .collect();
+            local_labels.push(LocalLabel {
+                span: observer_local_decl.source_info.span,
+                destructors,
+                name,
+                is_generated_name,
+                is_dropped_first_edition_2024: false,
+            });
+        }
+
+        let span = local_labels[0].span;
+        tcx.emit_node_span_lint(
+            lint::builtin::TAIL_EXPR_DROP_ORDER,
+            lint_root.unwrap_or(CRATE_HIR_ID),
+            span,
+            TailExprDropOrderLint { local_labels, drop_span, _epilogue: () },
+        );
+    }
+}
+
+/// Extract binding names if available for diagnosis
+fn collect_user_names(body: &Body<'_>) -> IndexMap<Local, Symbol> {
+    let mut names = IndexMap::default();
+    for var_debug_info in &body.var_debug_info {
+        if let mir::VarDebugInfoContents::Place(place) = &var_debug_info.value
+            && let Some(local) = place.local_or_deref_local()
+        {
+            names.entry(local).or_insert(var_debug_info.name);
+        }
+    }
+    names
+}
+
+/// Assign names for anonymous or temporary values for diagnosis
+fn assign_observables_names(
+    locals: impl IntoIterator<Item = Local>,
+    user_names: &IndexMap<Local, Symbol>,
+) -> IndexMap<Local, (String, bool)> {
+    let mut names = IndexMap::default();
+    let mut assigned_names = FxHashSet::default();
+    let mut idx = 0u64;
+    let mut fresh_name = || {
+        idx += 1;
+        (format!("#{idx}"), true)
+    };
+    for local in locals {
+        let name = if let Some(name) = user_names.get(&local) {
+            let name = name.as_str();
+            if assigned_names.contains(name) { fresh_name() } else { (name.to_owned(), false) }
+        } else {
+            fresh_name()
+        };
+        assigned_names.insert(name.0.clone());
+        names.insert(local, name);
+    }
+    names
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_tail_expr_drop_order)]
+struct TailExprDropOrderLint<'a> {
+    #[subdiagnostic]
+    local_labels: Vec<LocalLabel<'a>>,
+    #[label(mir_transform_drop_location)]
+    drop_span: Option<Span>,
+    #[note(mir_transform_note_epilogue)]
+    _epilogue: (),
+}
+
+struct LocalLabel<'a> {
+    span: Span,
+    name: &'a str,
+    is_generated_name: bool,
+    is_dropped_first_edition_2024: bool,
+    destructors: Vec<DestructorLabel<'a>>,
+}
+
+/// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order
+impl Subdiagnostic for LocalLabel<'_> {
+    fn add_to_diag_with<
+        G: rustc_errors::EmissionGuarantee,
+        F: rustc_errors::SubdiagMessageOp<G>,
+    >(
+        self,
+        diag: &mut rustc_errors::Diag<'_, G>,
+        f: &F,
+    ) {
+        diag.arg("name", self.name);
+        diag.arg("is_generated_name", self.is_generated_name);
+        diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024);
+        let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into());
+        diag.span_label(self.span, msg);
+        for dtor in self.destructors {
+            dtor.add_to_diag_with(diag, f);
+        }
+        let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue.into());
+        diag.span_label(self.span, msg);
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[note(mir_transform_tail_expr_dtor)]
+struct DestructorLabel<'a> {
+    #[primary_span]
+    span: Span,
+    dtor_kind: &'static str,
+    name: &'a str,
+}
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 55394e93a5c..fd49e956f43 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -92,6 +92,7 @@ impl RemoveNoopLandingPads {
                 | StatementKind::AscribeUserType(..)
                 | StatementKind::Coverage(..)
                 | StatementKind::ConstEvalCounter
+                | StatementKind::BackwardIncompatibleDropHint { .. }
                 | StatementKind::Nop => {
                     // These are all noops in a landing pad
                 }
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 2f723bccc19..6fd70fbe9b0 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -125,6 +125,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
             StatementKind::Coverage(_)
             | StatementKind::Intrinsic(_)
             | StatementKind::Nop
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::ConstEvalCounter => None,
         };
         if let Some(place_for_ty) = place_for_ty
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 7ed43547e11..4f312ed2aaa 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -523,7 +523,8 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
             }
 
             StatementKind::SetDiscriminant { ref place, variant_index: _ }
-            | StatementKind::Deinit(ref place) => {
+            | StatementKind::Deinit(ref place)
+            | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => {
                 self.visit_lhs(place, location);
             }
         }
@@ -560,6 +561,7 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod
                     StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
 
                     StatementKind::SetDiscriminant { ref place, .. }
+                    | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ }
                     | StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
                     StatementKind::Nop => false,
                     _ => true,
@@ -587,6 +589,20 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
         self.tcx
     }
 
+    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
+        if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } =
+            &mut statement.kind
+        {
+            self.visit_local(
+                &mut place.local,
+                PlaceContext::MutatingUse(MutatingUseContext::Store),
+                location,
+            );
+        } else {
+            self.super_statement(statement, location);
+        }
+    }
+
     fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
         *l = self.map[*l].unwrap();
     }
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 724238ecfc9..1739fdcc9af 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -343,6 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
             | StatementKind::Intrinsic(_)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
 
@@ -1493,6 +1494,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             | StatementKind::Coverage(_)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
+            | StatementKind::BackwardIncompatibleDropHint { .. }
             | StatementKind::Nop => {}
         }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index ebf7372926f..545ab15b945 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -102,7 +102,7 @@ where
 
     /// Assemble additional assumptions for an alias that are not included
     /// in the item bounds of the alias. For now, this is limited to the
-    /// `implied_const_bounds` for an associated type.
+    /// `explicit_implied_const_bounds` for an associated type.
     fn consider_additional_alias_assumptions(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
@@ -159,13 +159,6 @@ where
         goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution>;
 
-    /// A type is `PointerLike` if we can compute its layout, and that layout
-    /// matches the layout of `usize`.
-    fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution>;
-
     /// A type is a `FnPtr` if it is of `FnPtr` type.
     fn consider_builtin_fn_ptr_trait_candidate(
         ecx: &mut EvalCtxt<'_, D>,
@@ -449,9 +442,6 @@ where
                         ty::ClosureKind::FnOnce,
                     )
                 }
-                Some(TraitSolverLangItem::PointerLike) => {
-                    G::consider_builtin_pointer_like_candidate(self, goal)
-                }
                 Some(TraitSolverLangItem::FnPtrTrait) => {
                     G::consider_builtin_fn_ptr_trait_candidate(self, goal)
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 282ca2fedbc..603a68eb890 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -84,12 +84,9 @@ where
         let cx = ecx.cx();
         let mut candidates = vec![];
 
-        // FIXME(const_trait_impl): We elaborate here because the implied const bounds
-        // aren't necessarily elaborated. We probably should prefix this query
-        // with `explicit_`...
         for clause in elaborate::elaborate(
             cx,
-            cx.implied_const_bounds(alias_ty.def_id)
+            cx.explicit_implied_const_bounds(alias_ty.def_id)
                 .iter_instantiated(cx, alias_ty.args)
                 .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
         ) {
@@ -210,13 +207,6 @@ where
         Err(NoSolution)
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        _goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("PointerLike is not const")
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 8a01659953d..6b407640426 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -363,13 +363,6 @@ where
         panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        panic!("`PointerLike` does not have an associated type: {:?}", goal);
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         _ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index e64d4eed9d8..ce16258d180 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -248,32 +248,6 @@ where
         )
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        let cx = ecx.cx();
-        // But if there are inference variables, we have to wait until it's resolved.
-        if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() {
-            return ecx.forced_ambiguity(MaybeCause::Ambiguity);
-        }
-
-        if cx.layout_is_pointer_like(
-            ecx.typing_mode(goal.param_env),
-            goal.param_env,
-            goal.predicate.self_ty(),
-        ) {
-            ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
-                .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
-        } else {
-            Err(NoSolution)
-        }
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index ef259703f0c..cafd4b6dca2 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -216,6 +216,9 @@ parse_expected_identifier_found_doc_comment = expected identifier, found doc com
 parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
 parse_expected_identifier_found_keyword = expected identifier, found keyword
 parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
+parse_expected_identifier_found_metavar = expected identifier, found metavariable
+# This one deliberately doesn't print a token.
+parse_expected_identifier_found_metavar_str = expected identifier, found metavariable
 parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
 parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
 parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
@@ -227,6 +230,8 @@ parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyw
 
 parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
 parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
+# This one deliberately doesn't print a token.
+parse_expected_semi_found_metavar_str = expected `;`, found metavariable
 parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
 parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
 parse_expected_semi_found_str = expected `;`, found `{$token}`
@@ -864,6 +869,8 @@ parse_unexpected_token_after_not_logical = use `!` to perform logical negation
 parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
 parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
 parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
+# This one deliberately doesn't print a token.
+parse_unexpected_token_after_struct_name_found_metavar = expected `where`, `{"{"}`, `(`, or `;` after struct name, found metavar
 parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
 
 parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 37eb463cba6..9bdb99dc000 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1086,6 +1086,8 @@ pub(crate) enum ExpectedIdentifierFound {
     ReservedKeyword(#[primary_span] Span),
     #[label(parse_expected_identifier_found_doc_comment)]
     DocComment(#[primary_span] Span),
+    #[label(parse_expected_identifier_found_metavar)]
+    MetaVar(#[primary_span] Span),
     #[label(parse_expected_identifier)]
     Other(#[primary_span] Span),
 }
@@ -1099,6 +1101,7 @@ impl ExpectedIdentifierFound {
             Some(TokenDescription::Keyword) => ExpectedIdentifierFound::Keyword,
             Some(TokenDescription::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword,
             Some(TokenDescription::DocComment) => ExpectedIdentifierFound::DocComment,
+            Some(TokenDescription::MetaVar(_)) => ExpectedIdentifierFound::MetaVar,
             None => ExpectedIdentifierFound::Other,
         })(span)
     }
@@ -1117,6 +1120,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
     fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
         let token_descr = TokenDescription::from_token(&self.token);
 
+        let mut add_token = true;
         let mut diag = Diag::new(dcx, level, match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
                 fluent::parse_expected_identifier_found_reserved_identifier_str
@@ -1128,10 +1132,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
             Some(TokenDescription::DocComment) => {
                 fluent::parse_expected_identifier_found_doc_comment_str
             }
+            Some(TokenDescription::MetaVar(_)) => {
+                add_token = false;
+                fluent::parse_expected_identifier_found_metavar_str
+            }
             None => fluent::parse_expected_identifier_found_str,
         });
         diag.span(self.span);
-        diag.arg("token", self.token);
+        if add_token {
+            diag.arg("token", self.token);
+        }
 
         if let Some(sugg) = self.suggest_raw {
             sugg.add_to_diag(&mut diag);
@@ -1171,6 +1181,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
     fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
         let token_descr = TokenDescription::from_token(&self.token);
 
+        let mut add_token = true;
         let mut diag = Diag::new(dcx, level, match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
                 fluent::parse_expected_semi_found_reserved_identifier_str
@@ -1180,10 +1191,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
                 fluent::parse_expected_semi_found_reserved_keyword_str
             }
             Some(TokenDescription::DocComment) => fluent::parse_expected_semi_found_doc_comment_str,
+            Some(TokenDescription::MetaVar(_)) => {
+                add_token = false;
+                fluent::parse_expected_semi_found_metavar_str
+            }
             None => fluent::parse_expected_semi_found_str,
         });
         diag.span(self.span);
-        diag.arg("token", self.token);
+        if add_token {
+            diag.arg("token", self.token);
+        }
 
         if let Some(unexpected_token_label) = self.unexpected_token_label {
             diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token);
@@ -1925,6 +1942,12 @@ pub(crate) enum UnexpectedTokenAfterStructName {
         span: Span,
         token: Token,
     },
+    #[diag(parse_unexpected_token_after_struct_name_found_metavar)]
+    MetaVar {
+        #[primary_span]
+        #[label(parse_unexpected_token_after_struct_name)]
+        span: Span,
+    },
     #[diag(parse_unexpected_token_after_struct_name_found_other)]
     Other {
         #[primary_span]
@@ -1941,6 +1964,7 @@ impl UnexpectedTokenAfterStructName {
             Some(TokenDescription::Keyword) => Self::Keyword { span, token },
             Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token },
             Some(TokenDescription::DocComment) => Self::DocComment { span, token },
+            Some(TokenDescription::MetaVar(_)) => Self::MetaVar { span },
             None => Self::Other { span, token },
         }
     }
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index d35c9c7bae7..7b21ffacc84 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -43,11 +43,19 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
         let mut buf = Vec::new();
         loop {
             match self.token.kind {
-                token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) {
-                    Ok(val) => val,
-                    Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
-                }),
+                token::OpenDelim(delim) => {
+                    // Invisible delimiters cannot occur here because `TokenTreesReader` parses
+                    // code directly from strings, with no macro expansion involved.
+                    debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
+                    buf.push(match self.lex_token_tree_open_delim(delim) {
+                        Ok(val) => val,
+                        Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
+                    })
+                }
                 token::CloseDelim(delim) => {
+                    // Invisible delimiters cannot occur here because `TokenTreesReader` parses
+                    // code directly from strings, with no macro expansion involved.
+                    debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
                     return (
                         open_spacing,
                         TokenStream::new(buf),
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index c85d0bd05cb..434f71beac2 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -510,8 +510,8 @@ fn make_attr_token_stream(
             FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => {
                 let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
                 let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
-                assert_eq!(
-                    open_delim, delim,
+                assert!(
+                    open_delim.eq_ignoring_invisible_origin(&delim),
                     "Mismatched open/close delims: open={open_delim:?} close={span:?}"
                 );
                 let dspan = DelimSpan::from_pair(open_sp, span);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0012db471ef..aa5e9586daf 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -49,7 +49,7 @@ pub(super) enum DestructuredFloat {
     /// 1.2 | 1.2e3
     MiddleDot(Symbol, Span, Span, Symbol, Span),
     /// Invalid
-    Error(ErrorGuaranteed),
+    Error,
 }
 
 impl<'a> Parser<'a> {
@@ -1005,7 +1005,7 @@ impl<'a> Parser<'a> {
                             self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
                         self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
                     }
-                    DestructuredFloat::Error(_) => base,
+                    DestructuredFloat::Error => base,
                 })
             }
             _ => {
@@ -1015,7 +1015,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn error_unexpected_after_dot(&self) -> ErrorGuaranteed {
+    fn error_unexpected_after_dot(&self) {
         let actual = pprust::token_to_string(&self.token);
         let span = self.token.span;
         let sm = self.psess.source_map();
@@ -1025,7 +1025,7 @@ impl<'a> Parser<'a> {
             }
             _ => (span, actual),
         };
-        self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual })
+        self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual });
     }
 
     /// We need an identifier or integer, but the next token is a float.
@@ -1111,8 +1111,8 @@ impl<'a> Parser<'a> {
             // 1.2e+3 | 1.2e-3
             [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
                 // See the FIXME about `TokenCursor` above.
-                let guar = self.error_unexpected_after_dot();
-                DestructuredFloat::Error(guar)
+                self.error_unexpected_after_dot();
+                DestructuredFloat::Error
             }
             _ => panic!("unexpected components in a float token: {components:?}"),
         }
@@ -1178,7 +1178,7 @@ impl<'a> Parser<'a> {
                                 fields.insert(start_idx, Ident::new(symbol2, span2));
                                 fields.insert(start_idx, Ident::new(symbol1, span1));
                             }
-                            DestructuredFloat::Error(_) => {
+                            DestructuredFloat::Error => {
                                 trailing_dot = None;
                                 fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
                             }
@@ -3591,11 +3591,19 @@ impl<'a> Parser<'a> {
                         && !self.token.is_reserved_ident()
                         && self.look_ahead(1, |t| {
                             AssocOp::from_token(t).is_some()
-                                || matches!(t.kind, token::OpenDelim(_))
+                                || matches!(
+                                    t.kind,
+                                    token::OpenDelim(
+                                        Delimiter::Parenthesis
+                                            | Delimiter::Bracket
+                                            | Delimiter::Brace
+                                    )
+                                )
                                 || *t == token::Dot
                         })
                     {
-                        // Looks like they tried to write a shorthand, complex expression.
+                        // Looks like they tried to write a shorthand, complex expression,
+                        // E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
                         e.span_suggestion_verbose(
                             self.token.span.shrink_to_lo(),
                             "try naming a field",
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 042ee96bbe8..0ed8d152d2d 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -21,7 +21,9 @@ pub(crate) use item::FnParseMode;
 pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
 use path::PathStyle;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{
+    self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, Token, TokenKind,
+};
 use rustc_ast::tokenstream::{
     AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor,
 };
@@ -317,7 +319,7 @@ impl TokenCursor {
                             spacing,
                             delim,
                         ));
-                        if delim != Delimiter::Invisible {
+                        if !delim.skip() {
                             return (Token::new(token::OpenDelim(delim), sp.open), spacing.open);
                         }
                         // No open delimiter to return; continue on to the next iteration.
@@ -326,7 +328,7 @@ impl TokenCursor {
             } else if let Some((tree_cursor, span, spacing, delim)) = self.stack.pop() {
                 // We have exhausted this token stream. Move back to its parent token stream.
                 self.tree_cursor = tree_cursor;
-                if delim != Delimiter::Invisible {
+                if !delim.skip() {
                     return (Token::new(token::CloseDelim(delim), span.close), spacing.close);
                 }
                 // No close delimiter to return; continue on to the next iteration.
@@ -410,6 +412,12 @@ pub(super) enum TokenDescription {
     Keyword,
     ReservedKeyword,
     DocComment,
+
+    // Expanded metavariables are wrapped in invisible delimiters which aren't
+    // pretty-printed. In error messages we must handle these specially
+    // otherwise we get confusing things in messages like "expected `(`, found
+    // ``". It's better to say e.g. "expected `(`, found type metavariable".
+    MetaVar(MetaVarKind),
 }
 
 impl TokenDescription {
@@ -419,26 +427,29 @@ impl TokenDescription {
             _ if token.is_used_keyword() => Some(TokenDescription::Keyword),
             _ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword),
             token::DocComment(..) => Some(TokenDescription::DocComment),
+            token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
+                Some(TokenDescription::MetaVar(kind))
+            }
             _ => None,
         }
     }
 }
 
 pub fn token_descr(token: &Token) -> String {
-    let name = pprust::token_to_string(token).to_string();
-
-    let kind = match (TokenDescription::from_token(token), &token.kind) {
-        (Some(TokenDescription::ReservedIdentifier), _) => Some("reserved identifier"),
-        (Some(TokenDescription::Keyword), _) => Some("keyword"),
-        (Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
-        (Some(TokenDescription::DocComment), _) => Some("doc comment"),
-        (None, TokenKind::NtIdent(..)) => Some("identifier"),
-        (None, TokenKind::NtLifetime(..)) => Some("lifetime"),
-        (None, TokenKind::Interpolated(node)) => Some(node.descr()),
-        (None, _) => None,
-    };
-
-    if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") }
+    let s = pprust::token_to_string(token).to_string();
+
+    match (TokenDescription::from_token(token), &token.kind) {
+        (Some(TokenDescription::ReservedIdentifier), _) => format!("reserved identifier `{s}`"),
+        (Some(TokenDescription::Keyword), _) => format!("keyword `{s}`"),
+        (Some(TokenDescription::ReservedKeyword), _) => format!("reserved keyword `{s}`"),
+        (Some(TokenDescription::DocComment), _) => format!("doc comment `{s}`"),
+        // Deliberately doesn't print `s`, which is empty.
+        (Some(TokenDescription::MetaVar(kind)), _) => format!("`{kind}` metavariable"),
+        (None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"),
+        (None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"),
+        (None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()),
+        (None, _) => format!("`{s}`"),
+    }
 }
 
 impl<'a> Parser<'a> {
@@ -1163,7 +1174,7 @@ impl<'a> Parser<'a> {
         }
         debug_assert!(!matches!(
             next.0.kind,
-            token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
+            token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
         ));
         self.inlined_bump_with(next)
     }
@@ -1187,7 +1198,7 @@ impl<'a> Parser<'a> {
                     match tree {
                         TokenTree::Token(token, _) => return looker(token),
                         &TokenTree::Delimited(dspan, _, delim, _) => {
-                            if delim != Delimiter::Invisible {
+                            if !delim.skip() {
                                 return looker(&Token::new(token::OpenDelim(delim), dspan.open));
                             }
                         }
@@ -1197,7 +1208,7 @@ impl<'a> Parser<'a> {
                     // The tree cursor lookahead went (one) past the end of the
                     // current token tree. Try to return a close delimiter.
                     if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
-                        && delim != Delimiter::Invisible
+                        && !delim.skip()
                     {
                         // We are not in the outermost token stream, so we have
                         // delimiters. Also, those delimiters are not skipped.
@@ -1216,7 +1227,7 @@ impl<'a> Parser<'a> {
             token = cursor.next().0;
             if matches!(
                 token.kind,
-                token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
+                token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
             ) {
                 continue;
             }
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 43c3de90d9d..8fb6f85d0dd 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -3,7 +3,9 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::Nonterminal::*;
 use rustc_ast::token::NtExprKind::*;
 use rustc_ast::token::NtPatKind::*;
-use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
+use rustc_ast::token::{
+    self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token,
+};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::PResult;
@@ -22,7 +24,28 @@ impl<'a> Parser<'a> {
     #[inline]
     pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
         /// Checks whether the non-terminal may contain a single (non-keyword) identifier.
-        fn may_be_ident(nt: &token::Nonterminal) -> bool {
+        fn may_be_ident(kind: MetaVarKind) -> bool {
+            match kind {
+                MetaVarKind::Stmt
+                | MetaVarKind::Pat(_)
+                | MetaVarKind::Expr { .. }
+                | MetaVarKind::Ty
+                | MetaVarKind::Literal // `true`, `false`
+                | MetaVarKind::Meta
+                | MetaVarKind::Path => true,
+
+                MetaVarKind::Item
+                | MetaVarKind::Block
+                | MetaVarKind::Vis => false,
+
+                MetaVarKind::Ident
+                | MetaVarKind::Lifetime
+                | MetaVarKind::TT => unreachable!(),
+            }
+        }
+
+        /// Old variant of `may_be_ident`. Being phased out.
+        fn nt_may_be_ident(nt: &Nonterminal) -> bool {
             match nt {
                 NtStmt(_)
                 | NtPat(_)
@@ -69,7 +92,8 @@ impl<'a> Parser<'a> {
                 | token::Ident(..)
                 | token::NtIdent(..)
                 | token::NtLifetime(..)
-                | token::Interpolated(_) => true,
+                | token::Interpolated(_)
+                | token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true,
                 _ => token.can_begin_type(),
             },
             NonterminalKind::Block => match &token.kind {
@@ -79,11 +103,29 @@ impl<'a> Parser<'a> {
                     NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
                     NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
                 },
+                token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
+                    MetaVarKind::Block
+                    | MetaVarKind::Stmt
+                    | MetaVarKind::Expr { .. }
+                    | MetaVarKind::Literal => true,
+                    MetaVarKind::Item
+                    | MetaVarKind::Pat(_)
+                    | MetaVarKind::Ty
+                    | MetaVarKind::Meta
+                    | MetaVarKind::Path
+                    | MetaVarKind::Vis => false,
+                    MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => {
+                        unreachable!()
+                    }
+                },
                 _ => false,
             },
             NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
                 token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
-                token::Interpolated(nt) => may_be_ident(nt),
+                token::Interpolated(nt) => nt_may_be_ident(nt),
+                token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
+                    may_be_ident(*kind)
+                }
                 _ => false,
             },
             NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 936e5235c55..cc0763ac751 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -465,7 +465,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         let fields: Vec<_>;
         match &pat.kind {
             PatKind::AscribeUserType { subpattern, .. }
-            | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
+            | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index ad825d7813d..466e190028a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1478,9 +1478,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 if segment_idx == 0 {
                     if name == kw::SelfLower {
                         let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
-                        module = Some(ModuleOrUniformRoot::Module(
-                            self.resolve_self(&mut ctxt, parent_scope.module),
-                        ));
+                        let self_mod = self.resolve_self(&mut ctxt, parent_scope.module);
+                        if let Some(res) = self_mod.res() {
+                            record_segment_res(self, res);
+                        }
+                        module = Some(ModuleOrUniformRoot::Module(self_mod));
                         continue;
                     }
                     if name == kw::PathRoot && ident.span.at_least_rust_2018() {
@@ -1497,7 +1499,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     }
                     if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate {
                         // `::a::b`, `crate::a::b` or `$crate::a::b`
-                        module = Some(ModuleOrUniformRoot::Module(self.resolve_crate_root(ident)));
+                        let crate_root = self.resolve_crate_root(ident);
+                        if let Some(res) = crate_root.res() {
+                            record_segment_res(self, res);
+                        }
+                        module = Some(ModuleOrUniformRoot::Module(crate_root));
                         continue;
                     }
                 }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index f6e6fd33c48..d60c56fee75 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1069,7 +1069,7 @@ impl OutputFilenames {
         self.with_directory_and_extension(&self.out_directory, extension)
     }
 
-    fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
+    pub fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
         let mut path = directory.join(&self.filestem);
         path.set_extension(extension);
         path
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d94b503de18..edee7b4468c 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -358,7 +358,7 @@ fn build_options<O: Default>(
 
 #[allow(non_upper_case_globals)]
 mod desc {
-    pub(crate) const parse_no_flag: &str = "no value";
+    pub(crate) const parse_no_value: &str = "no value";
     pub(crate) const parse_bool: &str =
         "one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`";
     pub(crate) const parse_opt_bool: &str = parse_bool;
@@ -462,14 +462,18 @@ pub mod parse {
     pub(crate) use super::*;
     pub(crate) const MAX_THREADS_CAP: usize = 256;
 
-    /// This is for boolean options that don't take a value and start with
-    /// `no-`. This style of option is deprecated.
-    pub(crate) fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
+    /// This is for boolean options that don't take a value, and are true simply
+    /// by existing on the command-line.
+    ///
+    /// This style of option is deprecated, and is mainly used by old options
+    /// beginning with `no-`.
+    pub(crate) fn parse_no_value(slot: &mut bool, v: Option<&str>) -> bool {
         match v {
             None => {
                 *slot = true;
                 true
             }
+            // Trying to specify a value is always forbidden.
             Some(_) => false,
         }
     }
@@ -1609,16 +1613,16 @@ options! {
         "perform LLVM link-time optimizations"),
     metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
         "metadata to mangle symbol names with"),
-    no_prepopulate_passes: bool = (false, parse_no_flag, [TRACKED],
+    no_prepopulate_passes: bool = (false, parse_no_value, [TRACKED],
         "give an empty list of passes to the pass manager"),
     no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "disable the use of the redzone"),
     #[rustc_lint_opt_deny_field_access("documented to do nothing")]
-    no_stack_check: bool = (false, parse_no_flag, [UNTRACKED],
+    no_stack_check: bool = (false, parse_no_value, [UNTRACKED],
         "this option is deprecated and does nothing"),
-    no_vectorize_loops: bool = (false, parse_no_flag, [TRACKED],
+    no_vectorize_loops: bool = (false, parse_no_value, [TRACKED],
         "disable loop vectorization optimization passes"),
-    no_vectorize_slp: bool = (false, parse_no_flag, [TRACKED],
+    no_vectorize_slp: bool = (false, parse_no_value, [TRACKED],
         "disable LLVM's SLP vectorization pass"),
     opt_level: String = ("0".to_string(), parse_string, [TRACKED],
         "optimization level (0-3, s, or z; default: 0)"),
@@ -1887,7 +1891,7 @@ options! {
     meta_stats: bool = (false, parse_bool, [UNTRACKED],
         "gather metadata statistics (default: no)"),
     metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
-        "stores metrics about the errors being emitted by rustc to disk"),
+        "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"),
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
@@ -1915,25 +1919,25 @@ options! {
         "dump facts from NLL analysis into side files (default: no)"),
     nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED],
         "the directory the NLL facts are dumped into (default: `nll-facts`)"),
-    no_analysis: bool = (false, parse_no_flag, [UNTRACKED],
+    no_analysis: bool = (false, parse_no_value, [UNTRACKED],
         "parse and expand the source, but run no analysis"),
-    no_codegen: bool = (false, parse_no_flag, [TRACKED_NO_CRATE_HASH],
+    no_codegen: bool = (false, parse_no_value, [TRACKED_NO_CRATE_HASH],
         "run all passes except codegen; no output"),
-    no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED],
+    no_generate_arange_section: bool = (false, parse_no_value, [TRACKED],
         "omit DWARF address ranges that give faster lookups"),
     no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED],
         "disable the compatibility version of the `implied_bounds_ty` query"),
-    no_jump_tables: bool = (false, parse_no_flag, [TRACKED],
+    no_jump_tables: bool = (false, parse_no_value, [TRACKED],
         "disable the jump tables and lookup tables that can be generated from a switch case lowering"),
-    no_leak_check: bool = (false, parse_no_flag, [UNTRACKED],
+    no_leak_check: bool = (false, parse_no_value, [UNTRACKED],
         "disable the 'leak check' for subtyping; unsound, but useful for tests"),
-    no_link: bool = (false, parse_no_flag, [TRACKED],
+    no_link: bool = (false, parse_no_value, [TRACKED],
         "compile without linking"),
-    no_parallel_backend: bool = (false, parse_no_flag, [UNTRACKED],
+    no_parallel_backend: bool = (false, parse_no_value, [UNTRACKED],
         "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
-    no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
+    no_profiler_runtime: bool = (false, parse_no_value, [TRACKED],
         "prevent automatic injection of the profiler_builtins crate"),
-    no_trait_vptr: bool = (false, parse_no_flag, [TRACKED],
+    no_trait_vptr: bool = (false, parse_no_value, [TRACKED],
         "disable generation of trait vptr in vtable for upcasting"),
     no_unique_section_names: bool = (false, parse_bool, [TRACKED],
         "do not use unique names for text and data sections when -Z function-sections is used"),
@@ -1991,7 +1995,7 @@ options! {
     proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread,
         parse_proc_macro_execution_strategy, [UNTRACKED],
         "how to run proc-macro code (default: same-thread)"),
-    profile_closures: bool = (false, parse_no_flag, [UNTRACKED],
+    profile_closures: bool = (false, parse_no_value, [UNTRACKED],
         "profile size of closures"),
     profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
@@ -2165,8 +2169,14 @@ written to standard error output)"),
         "enable unsound and buggy MIR optimizations (default: no)"),
     /// This name is kind of confusing: Most unstable options enable something themselves, while
     /// this just allows "normal" options to be feature-gated.
+    ///
+    /// The main check for `-Zunstable-options` takes place separately from the
+    /// usual parsing of `-Z` options (see [`crate::config::nightly_options`]),
+    /// so this boolean value is mostly used for enabling unstable _values_ of
+    /// stable options. That separate check doesn't handle boolean values, so
+    /// to avoid an inconsistent state we also forbid them here.
     #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")]
-    unstable_options: bool = (false, parse_bool, [UNTRACKED],
+    unstable_options: bool = (false, parse_no_value, [UNTRACKED],
         "adds unstable command line options to rustc interface (default: no)"),
     use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "use legacy .ctors section for initializers rather than .init_array"),
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 820d8a6be25..fcdf8703b14 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -151,6 +151,10 @@ impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> {
             mir::StatementKind::ConstEvalCounter => {
                 stable_mir::mir::StatementKind::ConstEvalCounter
             }
+            // BackwardIncompatibleDropHint has no semantics, so it is translated to Nop.
+            mir::StatementKind::BackwardIncompatibleDropHint { .. } => {
+                stable_mir::mir::StatementKind::Nop
+            }
             mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop,
         }
     }
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index fe09daf522c..36f9b4cff60 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -33,7 +33,7 @@ pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024";
 
 pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
 
-pub const LATEST_STABLE_EDITION: Edition = Edition::Edition2021;
+pub const LATEST_STABLE_EDITION: Edition = Edition::Edition2024;
 
 impl fmt::Display for Edition {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -62,7 +62,7 @@ impl Edition {
             Edition::Edition2015 => true,
             Edition::Edition2018 => true,
             Edition::Edition2021 => true,
-            Edition::Edition2024 => false,
+            Edition::Edition2024 => true,
         }
     }
 
diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs
index 55b65fb1caa..67345f0d47b 100644
--- a/compiler/rustc_target/src/callconv/aarch64.rs
+++ b/compiler/rustc_target/src/callconv/aarch64.rs
@@ -1,5 +1,10 @@
+use std::iter;
+
+use rustc_abi::{BackendRepr, Primitive};
+
 use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
 use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::spec::{HasTargetSpec, Target};
 
 /// Indicates the variant of the AArch64 ABI we are compiling for.
 /// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
@@ -15,7 +20,7 @@ pub(crate) enum AbiKind {
 fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
 where
     Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
+    C: HasDataLayout + HasTargetSpec,
 {
     arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
         let size = arg.layout.size;
@@ -27,7 +32,9 @@ where
 
         let valid_unit = match unit.kind {
             RegKind::Integer => false,
-            RegKind::Float => true,
+            // The softfloat ABI treats floats like integers, so they
+            // do not get homogeneous aggregate treatment.
+            RegKind::Float => cx.target_spec().abi != "softfloat",
             RegKind::Vector => size.bits() == 64 || size.bits() == 128,
         };
 
@@ -35,10 +42,42 @@ where
     })
 }
 
+fn softfloat_float_abi<Ty>(target: &Target, arg: &mut ArgAbi<'_, Ty>) {
+    if target.abi != "softfloat" {
+        return;
+    }
+    // Do *not* use the float registers for passing arguments, as that would make LLVM pick the ABI
+    // and its choice depends on whether `neon` instructions are enabled. Instead, we follow the
+    // AAPCS "softfloat" ABI, which specifies that floats should be passed as equivalently-sized
+    // integers. Nominally this only exists for "R" profile chips, but sometimes people don't want
+    // to use hardfloats even if the hardware supports them, so we do this for all softfloat
+    // targets.
+    if let BackendRepr::Scalar(s) = arg.layout.backend_repr
+        && let Primitive::Float(f) = s.primitive()
+    {
+        arg.cast_to(Reg { kind: RegKind::Integer, size: f.size() });
+    } else if let BackendRepr::ScalarPair(s1, s2) = arg.layout.backend_repr
+        && (matches!(s1.primitive(), Primitive::Float(_))
+            || matches!(s2.primitive(), Primitive::Float(_)))
+    {
+        // This case can only be reached for the Rust ABI, so we can do whatever we want here as
+        // long as it does not depend on target features (i.e., as long as we do not use float
+        // registers). So we pass small things in integer registers and large things via pointer
+        // indirection. This means we lose the nice "pass it as two arguments" optimization, but we
+        // currently just have to way to combine a `PassMode::Cast` with that optimization (and we
+        // need a cast since we want to pass the float as an int).
+        if arg.layout.size.bits() <= target.pointer_width.into() {
+            arg.cast_to(Reg { kind: RegKind::Integer, size: arg.layout.size });
+        } else {
+            arg.make_indirect();
+        }
+    }
+}
+
 fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
+    C: HasDataLayout + HasTargetSpec,
 {
     if !ret.layout.is_sized() {
         // Not touching this...
@@ -51,6 +90,7 @@ where
             // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
             ret.extend_integer_width_to(32)
         }
+        softfloat_float_abi(cx.target_spec(), ret);
         return;
     }
     if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
@@ -69,7 +109,7 @@ where
 fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
+    C: HasDataLayout + HasTargetSpec,
 {
     if !arg.layout.is_sized() {
         // Not touching this...
@@ -82,6 +122,8 @@ where
             // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
             arg.extend_integer_width_to(32);
         }
+        softfloat_float_abi(cx.target_spec(), arg);
+
         return;
     }
     if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
@@ -112,7 +154,7 @@ where
 pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
+    C: HasDataLayout + HasTargetSpec,
 {
     if !fn_abi.ret.is_ignore() {
         classify_ret(cx, &mut fn_abi.ret, kind);
@@ -125,3 +167,13 @@ where
         classify_arg(cx, arg, kind);
     }
 }
+
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
+where
+    Ty: TyAbiInterface<'a, C> + Copy,
+    C: HasDataLayout + HasTargetSpec,
+{
+    for arg in fn_abi.args.iter_mut().chain(iter::once(&mut fn_abi.ret)) {
+        softfloat_float_abi(cx.target_spec(), arg);
+    }
+}
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index aa639f1624f..fb0fe402934 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -738,6 +738,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "x86" => x86::compute_rust_abi_info(cx, self, abi),
             "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi),
             "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi),
+            "aarch64" => aarch64::compute_rust_abi_info(cx, self),
             _ => {}
         };
 
diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs
index 502e7331267..c99eb9226ef 100644
--- a/compiler/rustc_target/src/callconv/s390x.rs
+++ b/compiler/rustc_target/src/callconv/s390x.rs
@@ -1,12 +1,16 @@
-// FIXME: The assumes we're using the non-vector ABI, i.e., compiling
-// for a pre-z13 machine or using -mno-vx.
+// Reference: ELF Application Binary Interface s390x Supplement
+// https://github.com/IBM/s390x-abi
 
-use crate::abi::call::{ArgAbi, FnAbi, Reg};
-use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind};
+use crate::abi::{BackendRepr, HasDataLayout, TyAbiInterface};
 use crate::spec::HasTargetSpec;
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
-    if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
+    let size = ret.layout.size;
+    if size.bits() <= 128 && matches!(ret.layout.backend_repr, BackendRepr::Vector { .. }) {
+        return;
+    }
+    if !ret.layout.is_aggregate() && size.bits() <= 64 {
         ret.extend_integer_width_to(64);
     } else {
         ret.make_indirect();
@@ -32,19 +36,25 @@ where
         }
         return;
     }
-    if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 {
+
+    let size = arg.layout.size;
+    if size.bits() <= 128 && arg.layout.is_single_vector_element(cx, size) {
+        arg.cast_to(Reg { kind: RegKind::Vector, size });
+        return;
+    }
+    if !arg.layout.is_aggregate() && size.bits() <= 64 {
         arg.extend_integer_width_to(64);
         return;
     }
 
     if arg.layout.is_single_fp_element(cx) {
-        match arg.layout.size.bytes() {
+        match size.bytes() {
             4 => arg.cast_to(Reg::f32()),
             8 => arg.cast_to(Reg::f64()),
             _ => arg.make_indirect(),
         }
     } else {
-        match arg.layout.size.bytes() {
+        match size.bytes() {
             1 => arg.cast_to(Reg::i8()),
             2 => arg.cast_to(Reg::i16()),
             4 => arg.cast_to(Reg::i32()),
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
index 3efbb464836..a84a18a433f 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs
@@ -6,9 +6,6 @@ pub(crate) fn target() -> Target {
     base.endian = Endian::Big;
     // z10 is the oldest CPU supported by LLVM
     base.cpu = "z10".into();
-    // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector
-    // ABI. Pass the -vector feature string to LLVM to respect this assumption.
-    base.features = "-vector".into();
     base.max_atomic_width = Some(128);
     base.min_global_align = Some(16);
     base.stack_probes = StackProbeType::Inline;
diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
index 65b5c1167bd..4bde0fb729c 100644
--- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs
@@ -6,9 +6,6 @@ pub(crate) fn target() -> Target {
     base.endian = Endian::Big;
     // z10 is the oldest CPU supported by LLVM
     base.cpu = "z10".into();
-    // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector
-    // ABI. Pass the -vector feature string to LLVM to respect this assumption.
-    base.features = "-vector".into();
     base.max_atomic_width = Some(128);
     base.min_global_align = Some(16);
     base.static_position_independent_executables = true;
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
index a213adadbea..a70cebbd9c8 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
@@ -5,7 +5,8 @@ use crate::spec::{
 pub(crate) fn target() -> Target {
     // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests.
     let pre_link_args = LinkArgs::new();
-    let post_link_args = TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0"]);
+    let post_link_args =
+        TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0", "-sWASM_BIGINT"]);
 
     let opts = TargetOptions {
         os: "emscripten".into(),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
index 3a3716db350..f42188ec61a 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs
@@ -8,7 +8,7 @@ pub(crate) fn target() -> Target {
     base.vendor = "win7".into();
 
     Target {
-        llvm_target: "x86_64-win7-windows-msvc".into(),
+        llvm_target: "x86_64-pc-windows-msvc".into(),
         metadata: crate::spec::TargetMetadata {
             description: Some("64-bit Windows 7 support".into()),
             tier: Some(3),
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 a5e364d49f7..5ad15feadff 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1075,93 +1075,110 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
         // Autoderef is useful here because sometimes we box callables, etc.
         let Some((def_id_or_name, output, inputs)) =
-            (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| {
-                match *found.kind() {
-                    ty::FnPtr(sig_tys, _) => Some((
-                        DefIdOrName::Name("function pointer"),
-                        sig_tys.output(),
-                        sig_tys.inputs(),
-                    )),
-                    ty::FnDef(def_id, _) => {
-                        let fn_sig = found.fn_sig(self.tcx);
-                        Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
-                    }
-                    ty::Closure(def_id, args) => {
-                        let fn_sig = args.as_closure().sig();
-                        Some((
-                            DefIdOrName::DefId(def_id),
-                            fn_sig.output(),
-                            fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
-                        ))
-                    }
-                    ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
-                        self.tcx
-                            .item_super_predicates(def_id)
-                            .instantiate(self.tcx, args)
-                            .iter()
-                            .find_map(|pred| {
-                                if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
-                        && self.tcx.is_lang_item(proj.projection_term.def_id,LangItem::FnOnceOutput)
-                        // args tuple will always be args[1]
-                        && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
-                                {
-                                    Some((
-                                        DefIdOrName::DefId(def_id),
-                                        pred.kind().rebind(proj.term.expect_type()),
-                                        pred.kind().rebind(args.as_slice()),
-                                    ))
-                                } else {
-                                    None
-                                }
-                            })
-                    }
-                    ty::Dynamic(data, _, ty::Dyn) => {
-                        data.iter().find_map(|pred| {
-                            if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+            (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| match *found.kind() {
+                ty::FnPtr(sig_tys, _) => Some((
+                    DefIdOrName::Name("function pointer"),
+                    sig_tys.output(),
+                    sig_tys.inputs(),
+                )),
+                ty::FnDef(def_id, _) => {
+                    let fn_sig = found.fn_sig(self.tcx);
+                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+                }
+                ty::Closure(def_id, args) => {
+                    let fn_sig = args.as_closure().sig();
+                    Some((
+                        DefIdOrName::DefId(def_id),
+                        fn_sig.output(),
+                        fn_sig.inputs().map_bound(|inputs| inputs[0].tuple_fields().as_slice()),
+                    ))
+                }
+                ty::CoroutineClosure(def_id, args) => {
+                    let sig_parts = args.as_coroutine_closure().coroutine_closure_sig();
+                    Some((
+                        DefIdOrName::DefId(def_id),
+                        sig_parts.map_bound(|sig| {
+                            sig.to_coroutine(
+                                self.tcx,
+                                args.as_coroutine_closure().parent_args(),
+                                // Just use infer vars here, since we  don't really care
+                                // what these types are, just that we're returning a coroutine.
+                                self.next_ty_var(DUMMY_SP),
+                                self.tcx.coroutine_for_closure(def_id),
+                                self.next_ty_var(DUMMY_SP),
+                            )
+                        }),
+                        sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),
+                    ))
+                }
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
+                    .tcx
+                    .item_super_predicates(def_id)
+                    .instantiate(self.tcx, args)
+                    .iter()
+                    .find_map(|pred| {
+                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
+                            && self
+                                .tcx
+                                .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
+                            // args tuple will always be args[1]
+                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
+                        {
+                            Some((
+                                DefIdOrName::DefId(def_id),
+                                pred.kind().rebind(proj.term.expect_type()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
+                        } else {
+                            None
+                        }
+                    }),
+                ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| {
+                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
                         && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)
                         // for existential projection, args are shifted over by 1
                         && let ty::Tuple(args) = proj.args.type_at(0).kind()
-                            {
-                                Some((
-                                    DefIdOrName::Name("trait object"),
-                                    pred.rebind(proj.term.expect_type()),
-                                    pred.rebind(args.as_slice()),
-                                ))
-                            } else {
-                                None
-                            }
-                        })
+                    {
+                        Some((
+                            DefIdOrName::Name("trait object"),
+                            pred.rebind(proj.term.expect_type()),
+                            pred.rebind(args.as_slice()),
+                        ))
+                    } else {
+                        None
                     }
-                    ty::Param(param) => {
-                        let generics = self.tcx.generics_of(body_id);
-                        let name = if generics.count() > param.index as usize
-                            && let def = generics.param_at(param.index as usize, self.tcx)
-                            && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
-                            && def.name == param.name
+                }),
+                ty::Param(param) => {
+                    let generics = self.tcx.generics_of(body_id);
+                    let name = if generics.count() > param.index as usize
+                        && let def = generics.param_at(param.index as usize, self.tcx)
+                        && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
+                        && def.name == param.name
+                    {
+                        DefIdOrName::DefId(def.def_id)
+                    } else {
+                        DefIdOrName::Name("type parameter")
+                    };
+                    param_env.caller_bounds().iter().find_map(|pred| {
+                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
+                            && self
+                                .tcx
+                                .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
+                            && proj.projection_term.self_ty() == found
+                            // args tuple will always be args[1]
+                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
                         {
-                            DefIdOrName::DefId(def.def_id)
+                            Some((
+                                name,
+                                pred.kind().rebind(proj.term.expect_type()),
+                                pred.kind().rebind(args.as_slice()),
+                            ))
                         } else {
-                            DefIdOrName::Name("type parameter")
-                        };
-                        param_env.caller_bounds().iter().find_map(|pred| {
-                            if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
-                        && self.tcx.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
-                        && proj.projection_term.self_ty() == found
-                        // args tuple will always be args[1]
-                        && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
-                            {
-                                Some((
-                                    name,
-                                    pred.kind().rebind(proj.term.expect_type()),
-                                    pred.kind().rebind(args.as_slice()),
-                                ))
-                            } else {
-                                None
-                            }
-                        })
-                    }
-                    _ => None,
+                            None
+                        }
+                    })
                 }
+                _ => None,
             })
         else {
             return None;
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index cb36f1a62db..27d3ec160ca 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -27,6 +27,11 @@ pub fn evaluate_host_effect_obligation<'tcx>(
         );
     }
 
+    // Force ambiguity for infer self ty.
+    if obligation.predicate.self_ty().is_ty_var() {
+        return Err(EvaluationFailure::Ambiguous);
+    }
+
     match evaluate_host_effect_from_bounds(selcx, obligation) {
         Ok(result) => return Ok(result),
         Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 1e0c487c4d4..41d430f06df 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -91,14 +91,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             } else if tcx.is_lang_item(def_id, LangItem::Sized) {
                 // Sized is never implementable by end-users, it is
                 // always automatically computed.
-
-                // FIXME: Consider moving this check to the top level as it
-                // may also be useful for predicates other than `Sized`
-                // Error type cannot possibly implement `Sized` (fixes #123154)
-                if let Err(e) = obligation.predicate.skip_binder().self_ty().error_reported() {
-                    return Err(SelectionError::Overflow(e.into()));
-                }
-
                 let sized_conditions = self.sized_conditions(obligation);
                 self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::Unsize) {
@@ -111,8 +103,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::Tuple) {
                 self.assemble_candidate_for_tuple(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::PointerLike) {
-                self.assemble_candidate_for_pointer_like(obligation, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) {
                 self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
             } else {
@@ -232,13 +222,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<(), SelectionError<'tcx>> {
         debug!(?stack.obligation);
 
-        // An error type will unify with anything. So, avoid
-        // matching an error type with `ParamCandidate`.
-        // This helps us avoid spurious errors like issue #121941.
-        if stack.obligation.predicate.references_error() {
-            return Ok(());
-        }
-
         let bounds = stack
             .obligation
             .param_env
@@ -565,19 +548,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        // Essentially any user-written impl will match with an error type,
-        // so creating `ImplCandidates` isn't useful. However, we might
-        // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`)
-        // This helps us avoid overflow: see issue #72839
-        // Since compilation is already guaranteed to fail, this is just
-        // to try to show the 'nicest' possible errors to the user.
-        // We don't check for errors in the `ParamEnv` - in practice,
-        // it seems to cause us to be overly aggressive in deciding
-        // to give up searching for candidates, leading to spurious errors.
-        if obligation.predicate.references_error() {
-            return;
-        }
-
         let drcx = DeepRejectCtxt::relate_rigid_infer(self.tcx());
         let obligation_args = obligation.predicate.skip_binder().trait_ref.args;
         self.tcx().for_each_relevant_impl(
@@ -1216,35 +1186,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    fn assemble_candidate_for_pointer_like(
-        &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) {
-        // The regions of a type don't affect the size of the type
-        let tcx = self.tcx();
-        let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty());
-
-        // But if there are inference variables, we have to wait until it's resolved.
-        if (obligation.param_env, self_ty).has_non_region_infer() {
-            candidates.ambiguous = true;
-            return;
-        }
-
-        // We should erase regions from both the param-env and type, since both
-        // may have infer regions. Specifically, after canonicalizing and instantiating,
-        // early bound regions turn into region vars in both the new and old solver.
-        let key = self.infcx.pseudo_canonicalize_query(
-            tcx.erase_regions(obligation.param_env),
-            tcx.erase_regions(self_ty),
-        );
-        if let Ok(layout) = tcx.layout_of(key)
-            && layout.layout.is_pointer_like(&tcx.data_layout)
-        {
-            candidates.vec.push(BuiltinCandidate { has_nested: false });
-        }
-    }
-
     fn assemble_candidates_for_fn_ptr_trait(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5b4e895189b..e0c862a81f3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2487,10 +2487,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id);
 
         let trait_ref = impl_trait_header.trait_ref.instantiate(self.tcx(), impl_args);
-        if trait_ref.references_error() {
-            return Err(());
-        }
-
         debug!(?impl_trait_header);
 
         let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } =
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 5bf3dbcbc32..a9cd705465e 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -15,24 +15,24 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::codes::*;
 use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::bug;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{
-    self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode,
-};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
+use rustc_type_ir::solve::NoSolution;
 use specialization_graph::GraphExt;
 use tracing::{debug, instrument};
 
-use super::{SelectionContext, util};
 use crate::error_reporting::traits::to_pretty_impl_header;
 use crate::errors::NegativePositiveConflict;
-use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, coherence};
+use crate::traits::{
+    FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, coherence,
+    predicates_for_generics,
+};
 
 /// Information pertinent to an overlapping impl error.
 #[derive(Debug)]
@@ -87,9 +87,14 @@ pub fn translate_args<'tcx>(
     source_args: GenericArgsRef<'tcx>,
     target_node: specialization_graph::Node,
 ) -> GenericArgsRef<'tcx> {
-    translate_args_with_cause(infcx, param_env, source_impl, source_args, target_node, |_, _| {
-        ObligationCause::dummy()
-    })
+    translate_args_with_cause(
+        infcx,
+        param_env,
+        source_impl,
+        source_args,
+        target_node,
+        &ObligationCause::dummy(),
+    )
 }
 
 /// Like [translate_args], but obligations from the parent implementation
@@ -104,7 +109,7 @@ pub fn translate_args_with_cause<'tcx>(
     source_impl: DefId,
     source_args: GenericArgsRef<'tcx>,
     target_node: specialization_graph::Node,
-    cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
+    cause: &ObligationCause<'tcx>,
 ) -> GenericArgsRef<'tcx> {
     debug!(
         "translate_args({:?}, {:?}, {:?}, {:?})",
@@ -123,7 +128,7 @@ pub fn translate_args_with_cause<'tcx>(
             }
 
             fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
-                .unwrap_or_else(|()| {
+                .unwrap_or_else(|_| {
                     bug!(
                         "When translating generic parameters from {source_impl:?} to \
                         {target_impl:?}, the expected specialization failed to hold"
@@ -137,6 +142,84 @@ pub fn translate_args_with_cause<'tcx>(
     source_args.rebase_onto(infcx.tcx, source_impl, target_args)
 }
 
+/// Attempt to fulfill all obligations of `target_impl` after unification with
+/// `source_trait_ref`. If successful, returns the generic parameters for *all* the
+/// generics of `target_impl`, including both those needed to unify with
+/// `source_trait_ref` and those whose identity is determined via a where
+/// clause in the impl.
+fn fulfill_implication<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    source_trait_ref: ty::TraitRef<'tcx>,
+    source_impl: DefId,
+    target_impl: DefId,
+    cause: &ObligationCause<'tcx>,
+) -> Result<GenericArgsRef<'tcx>, NoSolution> {
+    debug!(
+        "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
+        param_env, source_trait_ref, target_impl
+    );
+
+    let ocx = ObligationCtxt::new(infcx);
+    let source_trait_ref = ocx.normalize(cause, param_env, source_trait_ref);
+
+    if !ocx.select_all_or_error().is_empty() {
+        infcx.dcx().span_delayed_bug(
+            infcx.tcx.def_span(source_impl),
+            format!("failed to fully normalize {source_trait_ref}"),
+        );
+        return Err(NoSolution);
+    }
+
+    let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl);
+    let target_trait_ref = ocx.normalize(
+        cause,
+        param_env,
+        infcx
+            .tcx
+            .impl_trait_ref(target_impl)
+            .expect("expected source impl to be a trait impl")
+            .instantiate(infcx.tcx, target_args),
+    );
+
+    // do the impls unify? If not, no specialization.
+    ocx.eq(cause, param_env, source_trait_ref, target_trait_ref)?;
+
+    // Now check that the source trait ref satisfies all the where clauses of the target impl.
+    // This is not just for correctness; we also need this to constrain any params that may
+    // only be referenced via projection predicates.
+    let predicates = ocx.normalize(
+        cause,
+        param_env,
+        infcx.tcx.predicates_of(target_impl).instantiate(infcx.tcx, target_args),
+    );
+    let obligations = predicates_for_generics(|_, _| cause.clone(), param_env, predicates);
+    ocx.register_obligations(obligations);
+
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        // no dice!
+        debug!(
+            "fulfill_implication: for impls on {:?} and {:?}, \
+                 could not fulfill: {:?} given {:?}",
+            source_trait_ref,
+            target_trait_ref,
+            errors,
+            param_env.caller_bounds()
+        );
+        return Err(NoSolution);
+    }
+
+    debug!(
+        "fulfill_implication: an impl for {:?} specializes {:?}",
+        source_trait_ref, target_trait_ref
+    );
+
+    // Now resolve the *generic parameters* we built for the target earlier, replacing
+    // the inference variables inside with whatever we got from fulfillment.
+    Ok(infcx.resolve_vars_if_possible(target_args))
+}
+
 pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool {
     tcx.features().specialization() || tcx.features().min_specialization()
 }
@@ -182,8 +265,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
         return false;
     }
 
-    // create a parameter environment corresponding to a (placeholder) instantiation of impl1
-    let penv = tcx.param_env(impl1_def_id);
+    // create a parameter environment corresponding to an identity instantiation of impl1,
+    // i.e. the most generic instantiation of impl1.
+    let param_env = tcx.param_env(impl1_def_id);
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
     let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
@@ -191,90 +275,15 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
     // Attempt to prove that impl2 applies, given all of the above.
     fulfill_implication(
         &infcx,
-        penv,
+        param_env,
         impl1_trait_header.trait_ref.instantiate_identity(),
         impl1_def_id,
         impl2_def_id,
-        |_, _| ObligationCause::dummy(),
+        &ObligationCause::dummy(),
     )
     .is_ok()
 }
 
-/// Attempt to fulfill all obligations of `target_impl` after unification with
-/// `source_trait_ref`. If successful, returns the generic parameters for *all* the
-/// generics of `target_impl`, including both those needed to unify with
-/// `source_trait_ref` and those whose identity is determined via a where
-/// clause in the impl.
-fn fulfill_implication<'tcx>(
-    infcx: &InferCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    source_trait_ref: ty::TraitRef<'tcx>,
-    source_impl: DefId,
-    target_impl: DefId,
-    error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
-) -> Result<GenericArgsRef<'tcx>, ()> {
-    debug!(
-        "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
-        param_env, source_trait_ref, target_impl
-    );
-
-    let ocx = ObligationCtxt::new(infcx);
-    let source_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, source_trait_ref);
-
-    if !ocx.select_all_or_error().is_empty() {
-        infcx.dcx().span_delayed_bug(
-            infcx.tcx.def_span(source_impl),
-            format!("failed to fully normalize {source_trait_ref}"),
-        );
-    }
-
-    let source_trait_ref = infcx.resolve_vars_if_possible(source_trait_ref);
-    let source_trait = ImplSubject::Trait(source_trait_ref);
-
-    let selcx = SelectionContext::new(infcx);
-    let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl);
-    let (target_trait, obligations) =
-        util::impl_subject_and_oblig(&selcx, param_env, target_impl, target_args, error_cause);
-
-    // do the impls unify? If not, no specialization.
-    let Ok(InferOk { obligations: more_obligations, .. }) = infcx
-        .at(&ObligationCause::dummy(), param_env)
-        // Ok to use `Yes`, as all the generic params are already replaced by inference variables,
-        // which will match the opaque type no matter if it is defining or not.
-        // Any concrete type that would match the opaque would already be handled by coherence rules,
-        // and thus either be ok to match here and already have errored, or it won't match, in which
-        // case there is no issue anyway.
-        .eq(DefineOpaqueTypes::Yes, source_trait, target_trait)
-    else {
-        debug!("fulfill_implication: {:?} does not unify with {:?}", source_trait, target_trait);
-        return Err(());
-    };
-
-    // attempt to prove all of the predicates for impl2 given those for impl1
-    // (which are packed up in penv)
-    ocx.register_obligations(obligations.chain(more_obligations));
-
-    let errors = ocx.select_all_or_error();
-    if !errors.is_empty() {
-        // no dice!
-        debug!(
-            "fulfill_implication: for impls on {:?} and {:?}, \
-                 could not fulfill: {:?} given {:?}",
-            source_trait,
-            target_trait,
-            errors,
-            param_env.caller_bounds()
-        );
-        return Err(());
-    }
-
-    debug!("fulfill_implication: an impl for {:?} specializes {:?}", source_trait, target_trait);
-
-    // Now resolve the *generic parameters* we built for the target earlier, replacing
-    // the inference variables inside with whatever we got from fulfillment.
-    Ok(infcx.resolve_vars_if_possible(target_args))
-}
-
 /// Query provider for `specialization_graph_of`.
 pub(super) fn specialization_graph_provider(
     tcx: TyCtxt<'_>,
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index b7a2f20b769..da1045b664a 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -3,19 +3,16 @@ use std::collections::BTreeMap;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Diag;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::InferCtxt;
 pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt, Upcast,
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
 };
 use rustc_span::Span;
 use smallvec::{SmallVec, smallvec};
 use tracing::debug;
 
-use super::{NormalizeExt, ObligationCause, PredicateObligation, SelectionContext};
-
 ///////////////////////////////////////////////////////////////////////////
 // `TraitAliasExpander` iterator
 ///////////////////////////////////////////////////////////////////////////
@@ -166,34 +163,6 @@ impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
 // Other
 ///////////////////////////////////////////////////////////////////////////
 
-/// Instantiate all bound parameters of the impl subject with the given args,
-/// returning the resulting subject and all obligations that arise.
-/// The obligations are closed under normalization.
-pub(crate) fn impl_subject_and_oblig<'a, 'tcx>(
-    selcx: &SelectionContext<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    impl_def_id: DefId,
-    impl_args: GenericArgsRef<'tcx>,
-    cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
-) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
-    let subject = selcx.tcx().impl_subject(impl_def_id);
-    let subject = subject.instantiate(selcx.tcx(), impl_args);
-
-    let InferOk { value: subject, obligations: normalization_obligations1 } =
-        selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject);
-
-    let predicates = selcx.tcx().predicates_of(impl_def_id);
-    let predicates = predicates.instantiate(selcx.tcx(), impl_args);
-    let InferOk { value: predicates, obligations: normalization_obligations2 } =
-        selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates);
-    let impl_obligations = super::predicates_for_generics(cause, param_env, predicates);
-
-    let impl_obligations =
-        impl_obligations.chain(normalization_obligations1).chain(normalization_obligations2);
-
-    (subject, impl_obligations)
-}
-
 /// Casts a trait reference into a reference to one of its super
 /// traits; returns `None` if `target_trait_def_id` is not a
 /// supertrait.
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 03ab3a55486..469a4ac3e41 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -8,7 +8,7 @@ use rustc_middle::ty::util::{AlwaysRequiresDrop, needs_drop_components};
 use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt};
 use rustc_session::Limit;
 use rustc_span::sym;
-use tracing::debug;
+use tracing::{debug, instrument};
 
 use crate::errors::NeedsDropOverflow;
 
@@ -23,7 +23,7 @@ fn needs_drop_raw<'tcx>(
     // needs drop.
     let adt_has_dtor =
         |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant);
-    let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_dtor, false)
+    let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_dtor, false, false)
         .filter(filter_array_elements(tcx, query.typing_env))
         .next()
         .is_some();
@@ -41,7 +41,7 @@ fn needs_async_drop_raw<'tcx>(
     // it needs async drop.
     let adt_has_async_dtor =
         |adt_def: ty::AdtDef<'tcx>| adt_def.async_destructor(tcx).map(|_| DtorType::Significant);
-    let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_async_dtor, false)
+    let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_async_dtor, false, false)
         .filter(filter_array_elements(tcx, query.typing_env))
         .next()
         .is_some();
@@ -77,6 +77,7 @@ fn has_significant_drop_raw<'tcx>(
         query.typing_env,
         adt_consider_insignificant_dtor(tcx),
         true,
+        false,
     )
     .filter(filter_array_elements(tcx, query.typing_env))
     .next()
@@ -88,8 +89,8 @@ fn has_significant_drop_raw<'tcx>(
 struct NeedsDropTypes<'tcx, F> {
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
-    // Whether to reveal coroutine witnesses, this is set
-    // to `false` unless we compute `needs_drop` for a coroutine witness.
+    /// Whether to reveal coroutine witnesses, this is set
+    /// to `false` unless we compute `needs_drop` for a coroutine witness.
     reveal_coroutine_witnesses: bool,
     query_ty: Ty<'tcx>,
     seen_tys: FxHashSet<Ty<'tcx>>,
@@ -100,6 +101,9 @@ struct NeedsDropTypes<'tcx, F> {
     unchecked_tys: Vec<(Ty<'tcx>, usize)>,
     recursion_limit: Limit,
     adt_components: F,
+    /// Set this to true if an exhaustive list of types involved in
+    /// drop obligation is requested.
+    exhaustive: bool,
 }
 
 impl<'tcx, F> NeedsDropTypes<'tcx, F> {
@@ -107,6 +111,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
         tcx: TyCtxt<'tcx>,
         typing_env: ty::TypingEnv<'tcx>,
         ty: Ty<'tcx>,
+        exhaustive: bool,
         adt_components: F,
     ) -> Self {
         let mut seen_tys = FxHashSet::default();
@@ -114,14 +119,22 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
         Self {
             tcx,
             typing_env,
-            reveal_coroutine_witnesses: false,
+            reveal_coroutine_witnesses: exhaustive,
             seen_tys,
             query_ty: ty,
             unchecked_tys: vec![(ty, 0)],
             recursion_limit: tcx.recursion_limit(),
             adt_components,
+            exhaustive,
         }
     }
+
+    /// Called when `ty` is found to always require drop.
+    /// If the exhaustive flag is true, then `Ok(ty)` is returned like any other type.
+    /// Otherwise, `Err(AlwaysRequireDrop)` is returned, which will cause iteration to abort.
+    fn always_drop_component(&self, ty: Ty<'tcx>) -> NeedsDropResult<Ty<'tcx>> {
+        if self.exhaustive { Ok(ty) } else { Err(AlwaysRequiresDrop) }
+    }
 }
 
 impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
@@ -131,19 +144,22 @@ where
 {
     type Item = NeedsDropResult<Ty<'tcx>>;
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
         let tcx = self.tcx;
 
         while let Some((ty, level)) = self.unchecked_tys.pop() {
+            debug!(?ty, "needs_drop_components: inspect");
             if !self.recursion_limit.value_within_limit(level) {
                 // Not having a `Span` isn't great. But there's hopefully some other
                 // recursion limit error as well.
+                debug!("needs_drop_components: recursion limit exceeded");
                 tcx.dcx().emit_err(NeedsDropOverflow { query_ty: self.query_ty });
-                return Some(Err(AlwaysRequiresDrop));
+                return Some(self.always_drop_component(ty));
             }
 
             let components = match needs_drop_components(tcx, ty) {
-                Err(e) => return Some(Err(e)),
+                Err(AlwaysRequiresDrop) => return Some(self.always_drop_component(ty)),
                 Ok(components) => components,
             };
             debug!("needs_drop_components({:?}) = {:?}", ty, components);
@@ -171,7 +187,7 @@ where
                         if self.reveal_coroutine_witnesses {
                             queue_type(self, args.as_coroutine().witness());
                         } else {
-                            return Some(Err(AlwaysRequiresDrop));
+                            return Some(self.always_drop_component(ty));
                         }
                     }
                     ty::CoroutineWitness(def_id, args) => {
@@ -186,7 +202,7 @@ where
                         }
                     }
 
-                    _ if component.is_copy_modulo_regions(tcx, self.typing_env) => (),
+                    _ if component.is_copy_modulo_regions(tcx, self.typing_env) => {}
 
                     ty::Closure(_, args) => {
                         for upvar in args.as_closure().upvar_tys() {
@@ -205,7 +221,9 @@ where
                     // impl then check whether the field types need `Drop`.
                     ty::Adt(adt_def, args) => {
                         let tys = match (self.adt_components)(adt_def, args) {
-                            Err(e) => return Some(Err(e)),
+                            Err(AlwaysRequiresDrop) => {
+                                return Some(self.always_drop_component(ty));
+                            }
                             Ok(tys) => tys,
                         };
                         for required_ty in tys {
@@ -230,7 +248,8 @@ where
                     }
 
                     ty::Foreign(_) | ty::Dynamic(..) => {
-                        return Some(Err(AlwaysRequiresDrop));
+                        debug!("needs_drop_components: foreign or dynamic");
+                        return Some(self.always_drop_component(ty));
                     }
 
                     ty::Bool
@@ -280,6 +299,7 @@ fn drop_tys_helper<'tcx>(
     typing_env: ty::TypingEnv<'tcx>,
     adt_has_dtor: impl Fn(ty::AdtDef<'tcx>) -> Option<DtorType>,
     only_significant: bool,
+    exhaustive: bool,
 ) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
     fn with_query_cache<'tcx>(
         tcx: TyCtxt<'tcx>,
@@ -343,7 +363,7 @@ fn drop_tys_helper<'tcx>(
         .map(|v| v.into_iter())
     };
 
-    NeedsDropTypes::new(tcx, typing_env, ty, adt_components)
+    NeedsDropTypes::new(tcx, typing_env, ty, exhaustive, adt_components)
 }
 
 fn adt_consider_insignificant_dtor<'tcx>(
@@ -384,6 +404,7 @@ fn adt_drop_tys<'tcx>(
         ty::TypingEnv::non_body_analysis(tcx, def_id),
         adt_has_dtor,
         false,
+        false,
     )
     .collect::<Result<Vec<_>, _>>()
     .map(|components| tcx.mk_type_list(&components))
@@ -401,11 +422,31 @@ fn adt_significant_drop_tys(
         ty::TypingEnv::non_body_analysis(tcx, def_id),
         adt_consider_insignificant_dtor(tcx),
         true,
+        false,
     )
     .collect::<Result<Vec<_>, _>>()
     .map(|components| tcx.mk_type_list(&components))
 }
 
+#[instrument(level = "debug", skip(tcx), ret)]
+fn list_significant_drop_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> &'tcx ty::List<Ty<'tcx>> {
+    tcx.mk_type_list(
+        &drop_tys_helper(
+            tcx,
+            ty.value,
+            ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: ty.param_env },
+            adt_consider_insignificant_dtor(tcx),
+            true,
+            true,
+        )
+        .filter_map(|res| res.ok())
+        .collect::<Vec<_>>(),
+    )
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         needs_drop_raw,
@@ -413,6 +454,7 @@ pub(crate) fn provide(providers: &mut Providers) {
         has_significant_drop_raw,
         adt_drop_tys,
         adt_significant_drop_tys,
+        list_significant_drop_tys,
         ..*providers
     };
 }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 2127ba8a423..292e777f288 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -6,8 +6,7 @@ use rustc_index::bit_set::BitSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
-    TypeVisitor, Upcast,
+    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
 };
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
@@ -95,9 +94,6 @@ fn adt_sized_constraint<'tcx>(
     let tail_ty = tcx.type_of(tail_def.did).instantiate_identity();
 
     let constraint_ty = sized_constraint_for_ty(tcx, tail_ty)?;
-    if let Err(guar) = constraint_ty.error_reported() {
-        return Some(ty::EarlyBinder::bind(Ty::new_error(tcx, guar)));
-    }
 
     // perf hack: if there is a `constraint_ty: Sized` bound, then we know
     // that the type is sized and do not need to check it on the impl.
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 3fbce7886ed..2c1ad9de9aa 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -157,7 +157,7 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
             }
             // `T: ~const Trait` implies `T: ~const Supertrait`.
             ty::ClauseKind::HostEffect(data) => self.extend_deduped(
-                cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
+                cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
                     elaboratable.child(
                         trait_ref
                             .to_host_effect_clause(cx, data.constness)
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 6e6cf91d855..93b9c2e2892 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -13,7 +13,7 @@ use crate::lang_items::TraitSolverLangItem;
 use crate::relate::Relate;
 use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
-use crate::{self as ty, TypingMode, search_graph};
+use crate::{self as ty, search_graph};
 
 pub trait Interner:
     Sized
@@ -229,7 +229,7 @@ pub trait Interner:
         self,
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
-    fn implied_const_bounds(
+    fn explicit_implied_const_bounds(
         self,
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
@@ -278,13 +278,6 @@ pub trait Interner:
     fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
     fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
 
-    fn layout_is_pointer_like(
-        self,
-        typing_mode: TypingMode<Self>,
-        param_env: Self::ParamEnv,
-        ty: Self::Ty,
-    ) -> bool;
-
     type UnsizingParams: Deref<Target = BitSet<u32>>;
     fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
 
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index d6ca22a90a4..df43346065d 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -31,7 +31,6 @@ pub enum TraitSolverLangItem {
     Metadata,
     Option,
     PointeeTrait,
-    PointerLike,
     Poll,
     Sized,
     TransmuteTrait,
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 8a8e624e72a..5e3a3df0038 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -684,19 +684,6 @@ impl<I: Interner> ty::Binder<I, ProjectionPredicate<I>> {
         self.skip_binder().projection_term.trait_def_id(cx)
     }
 
-    /// Get the trait ref required for this projection to be well formed.
-    /// Note that for generic associated types the predicates of the associated
-    /// type also need to be checked.
-    #[inline]
-    pub fn required_poly_trait_ref(&self, cx: I) -> ty::Binder<I, TraitRef<I>> {
-        // Note: unlike with `TraitRef::to_poly_trait_ref()`,
-        // `self.0.trait_ref` is permitted to have escaping regions.
-        // This is because here `self` has a `Binder` and so does our
-        // return value, so we are preserving the number of binding
-        // levels.
-        self.map_bound(|predicate| predicate.projection_term.trait_ref(cx))
-    }
-
     pub fn term(&self) -> ty::Binder<I, I::Term> {
         self.map_bound(|predicate| predicate.term)
     }
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 70ecac4e17c..97996d5f0b2 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -158,9 +158,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.161"
+version = "0.2.162"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index ac3e4626ee5..ee60ec0fbac 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -191,6 +191,8 @@ use core::error::{self, Error};
 use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
+#[cfg(not(bootstrap))]
+use core::marker::PointerLike;
 use core::marker::{Tuple, Unsize};
 use core::mem::{self, SizedTypeProperties};
 use core::ops::{
@@ -2131,3 +2133,7 @@ impl<E: Error> Error for Box<E> {
         Error::provide(&**self, request);
     }
 }
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+impl<T> PointerLike for Box<T> {}
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 7839fe04b8d..041ff37897f 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -136,6 +136,7 @@
 #![feature(panic_internals)]
 #![feature(pattern)]
 #![feature(pin_coerce_unsized_trait)]
+#![feature(pointer_like_trait)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 4764d7f0b0f..71dcab3423c 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -10,11 +10,13 @@ use crate::convert::Infallible;
 use crate::error::Error;
 use crate::fmt;
 use crate::hash::{self, Hash};
+use crate::intrinsics::transmute_unchecked;
 use crate::iter::{UncheckedIterator, repeat_n};
 use crate::mem::{self, MaybeUninit};
 use crate::ops::{
     ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
 };
+use crate::ptr::{null, null_mut};
 use crate::slice::{Iter, IterMut};
 
 mod ascii;
@@ -606,8 +608,20 @@ impl<T, const N: usize> [T; N] {
     /// assert_eq!(strings.len(), 3);
     /// ```
     #[stable(feature = "array_methods", since = "1.77.0")]
-    pub fn each_ref(&self) -> [&T; N] {
-        from_trusted_iterator(self.iter())
+    #[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")]
+    pub const fn each_ref(&self) -> [&T; N] {
+        let mut buf = [null::<T>(); N];
+
+        // FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
+        let mut i = 0;
+        while i < N {
+            buf[i] = &raw const self[i];
+
+            i += 1;
+        }
+
+        // SAFETY: `*const T` has the same layout as `&T`, and we've also initialised each pointer as a valid reference.
+        unsafe { transmute_unchecked(buf) }
     }
 
     /// Borrows each element mutably and returns an array of mutable references
@@ -625,8 +639,20 @@ impl<T, const N: usize> [T; N] {
     /// assert_eq!(floats, [0.0, 2.7, -1.0]);
     /// ```
     #[stable(feature = "array_methods", since = "1.77.0")]
-    pub fn each_mut(&mut self) -> [&mut T; N] {
-        from_trusted_iterator(self.iter_mut())
+    #[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")]
+    pub const fn each_mut(&mut self) -> [&mut T; N] {
+        let mut buf = [null_mut::<T>(); N];
+
+        // FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
+        let mut i = 0;
+        while i < N {
+            buf[i] = &raw mut self[i];
+
+            i += 1;
+        }
+
+        // SAFETY: `*mut T` has the same layout as `&mut T`, and we've also initialised each pointer as a valid reference.
+        unsafe { transmute_unchecked(buf) }
     }
 
     /// Divides one array reference into two at an index.
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index da4f68a0de4..4fa719de5eb 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -22,23 +22,21 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6
 /// The *predecessor* operation moves towards values that compare lesser.
 #[unstable(feature = "step_trait", issue = "42168")]
 pub trait Step: Clone + PartialOrd + Sized {
-    /// Returns the number of *successor* steps required to get from `start` to `end`.
+    /// Returns the bounds on the number of *successor* steps required to get from `start` to `end`
+    /// like [`Iterator::size_hint()`][Iterator::size_hint()].
     ///
-    /// Returns `None` if the number of steps would overflow `usize`
-    /// (or is infinite, or if `end` would never be reached).
+    /// Returns `(usize::MAX, None)` if the number of steps would overflow `usize`, or is infinite.
     ///
     /// # Invariants
     ///
     /// For any `a`, `b`, and `n`:
     ///
-    /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::forward_checked(&a, n) == Some(b)`
-    /// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward_checked(&b, n) == Some(a)`
-    /// * `steps_between(&a, &b) == Some(n)` only if `a <= b`
-    ///   * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b`
-    ///   * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
-    ///     this is the case when it would require more than `usize::MAX` steps to get to `b`
-    /// * `steps_between(&a, &b) == None` if `a > b`
-    fn steps_between(start: &Self, end: &Self) -> Option<usize>;
+    /// * `steps_between(&a, &b) == (n, Some(n))` if and only if `Step::forward_checked(&a, n) == Some(b)`
+    /// * `steps_between(&a, &b) == (n, Some(n))` if and only if `Step::backward_checked(&b, n) == Some(a)`
+    /// * `steps_between(&a, &b) == (n, Some(n))` only if `a <= b`
+    ///   * Corollary: `steps_between(&a, &b) == (0, Some(0))` if and only if `a == b`
+    /// * `steps_between(&a, &b) == (0, None)` if `a > b`
+    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>);
 
     /// Returns the value that would be obtained by taking the *successor*
     /// of `self` `count` times.
@@ -169,7 +167,7 @@ pub trait Step: Clone + PartialOrd + Sized {
     /// For any `a`:
     ///
     /// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)`
-    /// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`,
+    /// * if there exists `b`, `n` such that `steps_between(&b, &a) == (n, Some(n))`,
     ///   it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`.
     ///   * Corollary: `Step::backward_unchecked(a, 0)` is always safe.
     ///
@@ -261,12 +259,13 @@ macro_rules! step_integer_impls {
                 step_unsigned_methods!();
 
                 #[inline]
-                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
                     if *start <= *end {
                         // This relies on $u_narrower <= usize
-                        Some((*end - *start) as usize)
+                        let steps = (*end - *start) as usize;
+                        (steps, Some(steps))
                     } else {
-                        None
+                        (0, None)
                     }
                 }
 
@@ -294,16 +293,17 @@ macro_rules! step_integer_impls {
                 step_signed_methods!($u_narrower);
 
                 #[inline]
-                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
                     if *start <= *end {
                         // This relies on $i_narrower <= usize
                         //
                         // Casting to isize extends the width but preserves the sign.
                         // Use wrapping_sub in isize space and cast to usize to compute
                         // the difference that might not fit inside the range of isize.
-                        Some((*end as isize).wrapping_sub(*start as isize) as usize)
+                        let steps = (*end as isize).wrapping_sub(*start as isize) as usize;
+                        (steps, Some(steps))
                     } else {
-                        None
+                        (0, None)
                     }
                 }
 
@@ -359,11 +359,15 @@ macro_rules! step_integer_impls {
                 step_unsigned_methods!();
 
                 #[inline]
-                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
                     if *start <= *end {
-                        usize::try_from(*end - *start).ok()
+                        if let Ok(steps) = usize::try_from(*end - *start) {
+                            (steps, Some(steps))
+                        } else {
+                            (usize::MAX, None)
+                        }
                     } else {
-                        None
+                        (0, None)
                     }
                 }
 
@@ -385,16 +389,22 @@ macro_rules! step_integer_impls {
                 step_signed_methods!($u_wider);
 
                 #[inline]
-                fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+                fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
                     if *start <= *end {
                         match end.checked_sub(*start) {
-                            Some(result) => usize::try_from(result).ok(),
+                            Some(result) => {
+                                if let Ok(steps) = usize::try_from(result) {
+                                    (steps, Some(steps))
+                                } else {
+                                    (usize::MAX, None)
+                                }
+                            }
                             // If the difference is too big for e.g. i128,
                             // it's also gonna be too big for usize with fewer bits.
-                            None => None,
+                            None => (usize::MAX, None),
                         }
                     } else {
-                        None
+                        (0, None)
                     }
                 }
 
@@ -433,18 +443,26 @@ step_integer_impls! {
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
 impl Step for char {
     #[inline]
-    fn steps_between(&start: &char, &end: &char) -> Option<usize> {
+    fn steps_between(&start: &char, &end: &char) -> (usize, Option<usize>) {
         let start = start as u32;
         let end = end as u32;
         if start <= end {
             let count = end - start;
             if start < 0xD800 && 0xE000 <= end {
-                usize::try_from(count - 0x800).ok()
+                if let Ok(steps) = usize::try_from(count - 0x800) {
+                    (steps, Some(steps))
+                } else {
+                    (usize::MAX, None)
+                }
             } else {
-                usize::try_from(count).ok()
+                if let Ok(steps) = usize::try_from(count) {
+                    (steps, Some(steps))
+                } else {
+                    (usize::MAX, None)
+                }
             }
         } else {
-            None
+            (0, None)
         }
     }
 
@@ -512,7 +530,7 @@ impl Step for char {
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
 impl Step for AsciiChar {
     #[inline]
-    fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> Option<usize> {
+    fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> (usize, Option<usize>) {
         Step::steps_between(&start.to_u8(), &end.to_u8())
     }
 
@@ -554,7 +572,7 @@ impl Step for AsciiChar {
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
 impl Step for Ipv4Addr {
     #[inline]
-    fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> Option<usize> {
+    fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> (usize, Option<usize>) {
         u32::steps_between(&start.to_bits(), &end.to_bits())
     }
 
@@ -586,7 +604,7 @@ impl Step for Ipv4Addr {
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
 impl Step for Ipv6Addr {
     #[inline]
-    fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> Option<usize> {
+    fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> (usize, Option<usize>) {
         u128::steps_between(&start.to_bits(), &end.to_bits())
     }
 
@@ -690,11 +708,8 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
 
     #[inline]
     default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
-        let available = if self.start <= self.end {
-            Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
-        } else {
-            0
-        };
+        let steps = Step::steps_between(&self.start, &self.end);
+        let available = steps.1.unwrap_or(steps.0);
 
         let taken = available.min(n);
 
@@ -731,11 +746,8 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
 
     #[inline]
     default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
-        let available = if self.start <= self.end {
-            Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
-        } else {
-            0
-        };
+        let steps = Step::steps_between(&self.start, &self.end);
+        let available = steps.1.unwrap_or(steps.0);
 
         let taken = available.min(n);
 
@@ -775,11 +787,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
 
     #[inline]
     fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
-        let available = if self.start <= self.end {
-            Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
-        } else {
-            0
-        };
+        let steps = Step::steps_between(&self.start, &self.end);
+        let available = steps.1.unwrap_or(steps.0);
 
         let taken = available.min(n);
 
@@ -819,11 +828,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
 
     #[inline]
     fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
-        let available = if self.start <= self.end {
-            Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
-        } else {
-            0
-        };
+        let steps = Step::steps_between(&self.start, &self.end);
+        let available = steps.1.unwrap_or(steps.0);
 
         let taken = available.min(n);
 
@@ -846,8 +852,7 @@ impl<A: Step> Iterator for ops::Range<A> {
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         if self.start < self.end {
-            let hint = Step::steps_between(&self.start, &self.end);
-            (hint.unwrap_or(usize::MAX), hint)
+            Step::steps_between(&self.start, &self.end)
         } else {
             (0, Some(0))
         }
@@ -856,7 +861,7 @@ impl<A: Step> Iterator for ops::Range<A> {
     #[inline]
     fn count(self) -> usize {
         if self.start < self.end {
-            Step::steps_between(&self.start, &self.end).expect("count overflowed usize")
+            Step::steps_between(&self.start, &self.end).1.expect("count overflowed usize")
         } else {
             0
         }
@@ -980,11 +985,11 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
 // Safety:
 // The following invariants for `Step::steps_between` exist:
 //
-// > * `steps_between(&a, &b) == Some(n)` only if `a <= b`
-// >   * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
+// > * `steps_between(&a, &b) == (n, Some(n))` only if `a <= b`
+// >   * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != (n, None)`;
 // >     this is the case when it would require more than `usize::MAX` steps to
 // >     get to `b`
-// > * `steps_between(&a, &b) == None` if `a > b`
+// > * `steps_between(&a, &b) == (0, None)` if `a > b`
 //
 // The first invariant is what is generally required for `TrustedLen` to be
 // sound. The note addendum satisfies an additional `TrustedLen` invariant.
@@ -1253,10 +1258,8 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
             return (0, Some(0));
         }
 
-        match Step::steps_between(&self.start, &self.end) {
-            Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
-            None => (usize::MAX, None),
-        }
+        let hint = Step::steps_between(&self.start, &self.end);
+        (hint.0.saturating_add(1), hint.1.and_then(|steps| steps.checked_add(1)))
     }
 
     #[inline]
@@ -1266,6 +1269,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
         }
 
         Step::steps_between(&self.start, &self.end)
+            .1
             .and_then(|steps| steps.checked_add(1))
             .expect("count overflowed usize")
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 3b8ac20e527..d30bf96cfd4 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -121,7 +121,6 @@
 #![feature(const_float_methods)]
 #![feature(const_heap)]
 #![feature(const_nonnull_new)]
-#![feature(const_pin_2)]
 #![feature(const_ptr_sub_ptr)]
 #![feature(const_raw_ptr_comparison)]
 #![feature(const_size_of_val)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 1c5c58d64a2..c8ea52a1fb0 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -981,6 +981,18 @@ pub trait Tuple {}
 )]
 pub trait PointerLike {}
 
+#[cfg(not(bootstrap))]
+marker_impls! {
+    #[unstable(feature = "pointer_like_trait", issue = "none")]
+    PointerLike for
+        usize,
+        {T} &T,
+        {T} &mut T,
+        {T} *const T,
+        {T} *mut T,
+        {T: PointerLike} crate::pin::Pin<T>,
+}
+
 /// A marker for types which can be used as types of `const` generic parameters.
 ///
 /// These types must have a proper equivalence relation (`Eq`) and it must be automatically
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index d3360c18207..6746f0b2b31 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -1594,16 +1594,15 @@ impl Ipv6Addr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ip)]
-    ///
     /// use std::net::Ipv6Addr;
     ///
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
     /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
     /// ```
-    #[unstable(feature = "ip", issue = "27709")]
     #[must_use]
     #[inline]
+    #[stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_unique_local(&self) -> bool {
         (self.segments()[0] & 0xfe00) == 0xfc00
     }
@@ -1665,8 +1664,6 @@ impl Ipv6Addr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ip)]
-    ///
     /// use std::net::Ipv6Addr;
     ///
     /// // The loopback address (`::1`) does not actually have link-local scope.
@@ -1680,9 +1677,10 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
     /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
     /// ```
-    #[unstable(feature = "ip", issue = "27709")]
     #[must_use]
     #[inline]
+    #[stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "ipv6_is_unique_local", since = "CURRENT_RUSTC_VERSION")]
     pub const fn is_unicast_link_local(&self) -> bool {
         (self.segments()[0] & 0xffc0) == 0xfe80
     }
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 254b306fcaa..c14c49a0d92 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1214,7 +1214,8 @@ impl<Ptr: Deref<Target: Unpin>> Pin<Ptr> {
     /// assert_eq!(*r, 5);
     /// ```
     #[inline(always)]
-    #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pin_into_inner", since = "1.39.0")]
     pub const fn into_inner(pin: Pin<Ptr>) -> Ptr {
         pin.__pointer
@@ -1503,7 +1504,8 @@ impl<Ptr: Deref> Pin<Ptr> {
     /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
     /// instead.
     #[inline(always)]
-    #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")]
     #[stable(feature = "pin_into_inner", since = "1.39.0")]
     pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr {
         pin.__pointer
diff --git a/library/core/tests/iter/traits/step.rs b/library/core/tests/iter/traits/step.rs
index 3d82a40cd29..bf935af397c 100644
--- a/library/core/tests/iter/traits/step.rs
+++ b/library/core/tests/iter/traits/step.rs
@@ -2,26 +2,37 @@ use core::iter::*;
 
 #[test]
 fn test_steps_between() {
-    assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize));
-    assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize));
-    assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize));
-    assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize));
-    assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize));
-    assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize));
+    assert_eq!(Step::steps_between(&20_u8, &200_u8), (180_usize, Some(180_usize)));
+    assert_eq!(Step::steps_between(&-20_i8, &80_i8), (100_usize, Some(100_usize)));
+    assert_eq!(Step::steps_between(&-120_i8, &80_i8), (200_usize, Some(200_usize)));
+    assert_eq!(
+        Step::steps_between(&20_u32, &4_000_100_u32),
+        (4_000_080_usize, Some(4_000_080_usize))
+    );
+    assert_eq!(Step::steps_between(&-20_i32, &80_i32), (100_usize, Some(100_usize)));
+    assert_eq!(
+        Step::steps_between(&-2_000_030_i32, &2_000_050_i32),
+        (4_000_080_usize, Some(4_000_080_usize))
+    );
 
     // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms
 
-    assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize));
-    assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize));
+    assert_eq!(Step::steps_between(&20_u128, &200_u128), (180_usize, Some(180_usize)));
+    assert_eq!(Step::steps_between(&-20_i128, &80_i128), (100_usize, Some(100_usize)));
     if cfg!(target_pointer_width = "64") {
-        assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX));
+        assert_eq!(
+            Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128),
+            (usize::MAX, Some(usize::MAX))
+        );
     }
-    assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None);
-    assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None);
+    assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), (usize::MAX, None));
+    assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), (usize::MAX, None));
     assert_eq!(
         Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,),
-        None,
+        (usize::MAX, None),
     );
+
+    assert_eq!(Step::steps_between(&100_u32, &10_u32), (0, None));
 }
 
 #[test]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index f515e9e4109..f7825571cd7 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -21,7 +21,6 @@
 #![feature(const_eval_select)]
 #![feature(const_heap)]
 #![feature(const_nonnull_new)]
-#![feature(const_pin_2)]
 #![feature(const_trait_impl)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index b732fdf1696..c1ab70b714a 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -34,7 +34,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
 addr2line = { version = "0.22.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.161", default-features = false, features = [
+libc = { version = "0.2.162", default-features = false, features = [
     'rustc-dep-of-std',
 ], public = true }
 
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 9f913eae095..fbfdb4fa023 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -153,7 +153,8 @@ impl<T> Cursor<T> {
     /// let reference = buff.get_mut();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut T {
+    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    pub const fn get_mut(&mut self) -> &mut T {
         &mut self.inner
     }
 
@@ -200,7 +201,8 @@ impl<T> Cursor<T> {
     /// assert_eq!(buff.position(), 4);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn set_position(&mut self, pos: u64) {
+    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    pub const fn set_position(&mut self, pos: u64) {
         self.pos = pos;
     }
 }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5b94f036248..9c4e6f296fe 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -658,6 +658,8 @@ pub mod arch {
     pub use std_detect::is_aarch64_feature_detected;
     #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")]
     pub use std_detect::is_arm_feature_detected;
+    #[unstable(feature = "is_loongarch_feature_detected", issue = "117425")]
+    pub use std_detect::is_loongarch_feature_detected;
     #[unstable(feature = "is_riscv_feature_detected", issue = "111192")]
     pub use std_detect::is_riscv_feature_detected;
     #[stable(feature = "simd_x86", since = "1.27.0")]
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 2d087c03b04..388b8a88a1a 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -173,16 +173,17 @@ impl Drop for OwnedFd {
     #[inline]
     fn drop(&mut self) {
         unsafe {
-            // Note that errors are ignored when closing a file descriptor. The
-            // reason for this is that if an error occurs we don't actually know if
-            // the file descriptor was closed or not, and if we retried (for
-            // something like EINTR), we might close another valid file descriptor
-            // opened after we closed ours.
-            // However, this is usually justified, as some of the major Unices
-            // do make sure to always close the FD, even when `close()` is interrupted,
-            // and the scenario is rare to begin with.
-            // Helpful link to an epic discussion by POSIX workgroup:
-            // http://austingroupbugs.net/view.php?id=529
+            // Note that errors are ignored when closing a file descriptor. According to POSIX 2024,
+            // we can and indeed should retry `close` on `EINTR`
+            // (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/close.html),
+            // but it is not clear yet how well widely-used implementations are conforming with this
+            // mandate since older versions of POSIX left the state of the FD after an `EINTR`
+            // unspecified. Ignoring errors is "fine" because some of the major Unices (in
+            // particular, Linux) do make sure to always close the FD, even when `close()` is
+            // interrupted, and the scenario is rare to begin with. If we retried on a
+            // not-POSIX-compliant implementation, the consequences could be really bad since we may
+            // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to
+            // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529
             #[cfg(not(target_os = "hermit"))]
             {
                 #[cfg(unix)]
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
index 0cc9cecb89d..1b83f4b0aee 100644
--- a/library/std/src/sys/pal/uefi/process.rs
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -18,6 +18,7 @@ use crate::{fmt, io};
 #[derive(Debug)]
 pub struct Command {
     prog: OsString,
+    args: Vec<OsString>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
 }
@@ -39,12 +40,11 @@ pub enum Stdio {
 
 impl Command {
     pub fn new(program: &OsStr) -> Command {
-        Command { prog: program.to_os_string(), stdout: None, stderr: None }
+        Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None }
     }
 
-    // FIXME: Implement arguments as reverse of parsing algorithm
-    pub fn arg(&mut self, _arg: &OsStr) {
-        panic!("unsupported")
+    pub fn arg(&mut self, arg: &OsStr) {
+        self.args.push(arg.to_os_string());
     }
 
     pub fn env_mut(&mut self) -> &mut CommandEnv {
@@ -72,7 +72,7 @@ impl Command {
     }
 
     pub fn get_args(&self) -> CommandArgs<'_> {
-        panic!("unsupported")
+        CommandArgs { iter: self.args.iter() }
     }
 
     pub fn get_envs(&self) -> CommandEnvs<'_> {
@@ -116,6 +116,12 @@ impl Command {
     pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
         let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
 
+        // UEFI adds the bin name by default
+        if !self.args.is_empty() {
+            let args = uefi_command_internal::create_args(&self.prog, &self.args);
+            cmd.set_args(args);
+        }
+
         // Setup Stdout
         let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
         let stdout = Self::create_pipe(stdout)?;
@@ -315,7 +321,7 @@ mod uefi_command_internal {
         stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
         stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
         st: OwnedTable<r_efi::efi::SystemTable>,
-        args: Option<Vec<u16>>,
+        args: Option<(*mut u16, usize)>,
     }
 
     impl Image {
@@ -449,20 +455,20 @@ mod uefi_command_internal {
             }
         }
 
-        pub fn set_args(&mut self, args: &OsStr) {
+        pub fn set_args(&mut self, args: Box<[u16]>) {
             let loaded_image: NonNull<loaded_image::Protocol> =
                 helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
 
-            let mut args = args.encode_wide().collect::<Vec<u16>>();
-            let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32;
+            let len = args.len();
+            let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
+            let ptr = Box::into_raw(args).as_mut_ptr();
 
             unsafe {
-                (*loaded_image.as_ptr()).load_options =
-                    args.as_mut_ptr() as *mut crate::ffi::c_void;
+                (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void;
                 (*loaded_image.as_ptr()).load_options_size = args_size;
             }
 
-            self.args = Some(args);
+            self.args = Some((ptr, len));
         }
 
         fn update_st_crc32(&mut self) -> io::Result<()> {
@@ -502,6 +508,10 @@ mod uefi_command_internal {
                     ((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
                 }
             }
+
+            if let Some((ptr, len)) = self.args {
+                let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) };
+            }
         }
     }
 
@@ -681,4 +691,38 @@ mod uefi_command_internal {
             }
         }
     }
+
+    pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
+        const QUOTE: u16 = 0x0022;
+        const SPACE: u16 = 0x0020;
+        const CARET: u16 = 0x005e;
+        const NULL: u16 = 0;
+
+        // This is the lower bound on the final length under the assumption that
+        // the arguments only contain ASCII characters.
+        let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum());
+
+        // Wrap program name in quotes to avoid any problems
+        res.push(QUOTE);
+        res.extend(prog.encode_wide());
+        res.push(QUOTE);
+        res.push(SPACE);
+
+        for arg in args {
+            // Wrap the argument in quotes to be treat as single arg
+            res.push(QUOTE);
+            for c in arg.encode_wide() {
+                // CARET in quotes is used to escape CARET or QUOTE
+                if c == QUOTE || c == CARET {
+                    res.push(CARET);
+                }
+                res.push(c);
+            }
+            res.push(QUOTE);
+
+            res.push(SPACE);
+        }
+
+        res.into_boxed_slice()
+    }
 }
diff --git a/library/std/src/sys/random/arc4random.rs b/library/std/src/sys/random/arc4random.rs
index ffabaafbee8..32467e9ebaa 100644
--- a/library/std/src/sys/random/arc4random.rs
+++ b/library/std/src/sys/random/arc4random.rs
@@ -12,7 +12,6 @@
 #[cfg(not(any(
     target_os = "haiku",
     target_os = "illumos",
-    target_os = "rtems",
     target_os = "solaris",
     target_os = "vita",
 )))]
@@ -22,7 +21,6 @@ use libc::arc4random_buf;
 #[cfg(any(
     target_os = "haiku", // See https://git.haiku-os.org/haiku/tree/headers/compatibility/bsd/stdlib.h
     target_os = "illumos", // See https://www.illumos.org/man/3C/arc4random
-    target_os = "rtems", // See https://docs.rtems.org/branches/master/bsp-howto/getentropy.html
     target_os = "solaris", // See https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html
     target_os = "vita", // See https://github.com/vitasdk/newlib/blob/b89e5bc183b516945f9ee07eef483ecb916e45ff/newlib/libc/include/stdlib.h#L74
 ))]
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index b2305b1eda7..a14446b3515 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -176,7 +176,7 @@ impl<'scope, 'env> Scope<'scope, 'env> {
     /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
     /// the panic payload.
     ///
-    /// If the join handle is dropped, the spawned thread will implicitly joined at the
+    /// If the join handle is dropped, the spawned thread will be implicitly joined at the
     /// end of the scope. In that case, if the spawned thread panics, [`scope`] will
     /// panic after all threads are joined.
     ///
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 24be705f481..8e088682f92 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1457,7 +1457,7 @@ impl Step for CodegenBackend {
         }
         let mut files = files.into_iter().filter(|f| {
             let filename = f.file_name().unwrap().to_str().unwrap();
-            is_dylib(filename) && filename.contains("rustc_codegen_")
+            is_dylib(f) && filename.contains("rustc_codegen_")
         });
         let codegen_backend = match files.next() {
             Some(f) => f,
@@ -1936,7 +1936,7 @@ impl Step for Assemble {
             let filename = f.file_name().into_string().unwrap();
 
             let is_proc_macro = proc_macros.contains(&filename);
-            let is_dylib_or_debug = is_dylib(&filename) || is_debug_info(&filename);
+            let is_dylib_or_debug = is_dylib(&f.path()) || 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
@@ -2089,7 +2089,7 @@ pub fn run_cargo(
             if filename.ends_with(".lib")
                 || filename.ends_with(".a")
                 || is_debug_info(&filename)
-                || is_dylib(&filename)
+                || is_dylib(Path::new(&*filename))
             {
                 // Always keep native libraries, rust dylibs and debuginfo
                 keep = true;
@@ -2189,7 +2189,7 @@ pub fn run_cargo(
             Some(triple) => triple.0.to_str().unwrap(),
             None => panic!("no output generated for {prefix:?} {extension:?}"),
         };
-        if is_dylib(path_to_add) {
+        if is_dylib(Path::new(path_to_add)) {
             let candidate = format!("{path_to_add}.lib");
             let candidate = PathBuf::from(candidate);
             if candidate.exists() {
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index c022285211f..a636c4a9ef1 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -436,13 +436,10 @@ impl Step for Rustc {
             if libdir_relative.to_str() != Some("bin") {
                 let libdir = builder.rustc_libdir(compiler);
                 for entry in builder.read_dir(&libdir) {
-                    let name = entry.file_name();
-                    if let Some(s) = name.to_str() {
-                        if is_dylib(s) {
-                            // Don't use custom libdir here because ^lib/ will be resolved again
-                            // with installer
-                            builder.install(&entry.path(), &image.join("lib"), 0o644);
-                        }
+                    if is_dylib(&entry.path()) {
+                        // Don't use custom libdir here because ^lib/ will be resolved again
+                        // with installer
+                        builder.install(&entry.path(), &image.join("lib"), 0o644);
                     }
                 }
             }
@@ -1026,7 +1023,7 @@ impl Step for PlainSourceTarball {
             let mut cmd = command(&builder.initial_cargo);
             cmd.arg("vendor").arg("--versioned-dirs");
 
-            for p in default_paths_to_vendor(builder) {
+            for (p, _) in default_paths_to_vendor(builder) {
                 cmd.arg("--sync").arg(p);
             }
 
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index a6dff7fde80..1a0a90564e6 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -211,12 +211,13 @@ impl Step for GenerateCopyright {
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let license_metadata = builder.ensure(CollectLicenseMetadata);
 
-        // Temporary location, it will be moved to the proper one once it's accurate.
         let dest = builder.out.join("COPYRIGHT.html");
+        let dest_libstd = builder.out.join("COPYRIGHT-library.html");
 
         let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
         cmd.env("LICENSE_METADATA", &license_metadata);
         cmd.env("DEST", &dest);
+        cmd.env("DEST_LIBSTD", &dest_libstd);
         cmd.env("OUT_DIR", &builder.out);
         cmd.env("CARGO", &builder.initial_cargo);
         cmd.run(builder);
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 532c8f767eb..dcea9f5f7d1 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2949,8 +2949,7 @@ impl Step for RemoteCopyLibs {
         // Push all our dylibs to the emulator
         for f in t!(builder.sysroot_target_libdir(compiler, target).read_dir()) {
             let f = t!(f);
-            let name = f.file_name().into_string().unwrap();
-            if helpers::is_dylib(&name) {
+            if helpers::is_dylib(&f.path()) {
                 command(&tool).arg("push").arg(f.path()).run(builder);
             }
         }
diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs
index 82a6b4d4f28..ce044c4a4a7 100644
--- a/src/bootstrap/src/core/build_steps/vendor.rs
+++ b/src/bootstrap/src/core/build_steps/vendor.rs
@@ -4,24 +4,26 @@ use crate::core::build_steps::tool::SUBMODULES_FOR_RUSTBOOK;
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::utils::exec::command;
 
-/// List of default paths used for vendoring for `x vendor` and dist tarballs.
-pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<PathBuf> {
-    let mut paths = vec![];
-    for p in [
-        "src/tools/cargo/Cargo.toml",
-        "src/tools/rust-analyzer/Cargo.toml",
-        "compiler/rustc_codegen_cranelift/Cargo.toml",
-        "compiler/rustc_codegen_gcc/Cargo.toml",
-        "library/Cargo.toml",
-        "src/bootstrap/Cargo.toml",
-        "src/tools/rustbook/Cargo.toml",
-        "src/tools/rustc-perf/Cargo.toml",
-        "src/tools/opt-dist/Cargo.toml",
-    ] {
-        paths.push(builder.src.join(p));
-    }
-
-    paths
+/// Returns the cargo workspaces to vendor for `x vendor` and dist tarballs.
+///
+/// Returns a `Vec` of `(path_to_manifest, submodules_required)` where
+/// `path_to_manifest` is the cargo workspace, and `submodules_required` is
+/// the set of submodules that must be available.
+pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<(PathBuf, Vec<&'static str>)> {
+    [
+        ("src/tools/cargo/Cargo.toml", vec!["src/tools/cargo"]),
+        ("src/tools/rust-analyzer/Cargo.toml", vec![]),
+        ("compiler/rustc_codegen_cranelift/Cargo.toml", vec![]),
+        ("compiler/rustc_codegen_gcc/Cargo.toml", vec![]),
+        ("library/Cargo.toml", vec![]),
+        ("src/bootstrap/Cargo.toml", vec![]),
+        ("src/tools/rustbook/Cargo.toml", SUBMODULES_FOR_RUSTBOOK.into()),
+        ("src/tools/rustc-perf/Cargo.toml", vec!["src/tools/rustc-perf"]),
+        ("src/tools/opt-dist/Cargo.toml", vec![]),
+    ]
+    .into_iter()
+    .map(|(path, submodules)| (builder.src.join(path), submodules))
+    .collect()
 }
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -56,13 +58,16 @@ impl Step for Vendor {
             cmd.arg("--versioned-dirs");
         }
 
+        let to_vendor = default_paths_to_vendor(builder);
         // These submodules must be present for `x vendor` to work.
-        for submodule in SUBMODULES_FOR_RUSTBOOK.iter().chain(["src/tools/cargo"].iter()) {
-            builder.build.require_submodule(submodule, None);
+        for (_, submodules) in &to_vendor {
+            for submodule in submodules {
+                builder.build.require_submodule(submodule, None);
+            }
         }
 
         // Sync these paths by default.
-        for p in default_paths_to_vendor(builder) {
+        for (p, _) in &to_vendor {
             cmd.arg("--sync").arg(p);
         }
 
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 3fb2330469a..9ca036a2afd 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -11,6 +11,7 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH};
 use std::{env, fs, io, str};
 
 use build_helper::util::fail;
+use object::read::archive::ArchiveFile;
 
 use crate::LldMode;
 use crate::core::builder::Builder;
@@ -53,8 +54,27 @@ pub fn exe(name: &str, target: TargetSelection) -> String {
 }
 
 /// Returns `true` if the file name given looks like a dynamic library.
-pub fn is_dylib(name: &str) -> bool {
-    name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll")
+pub fn is_dylib(path: &Path) -> bool {
+    path.extension().and_then(|ext| ext.to_str()).map_or(false, |ext| {
+        ext == "dylib" || ext == "so" || ext == "dll" || (ext == "a" && is_aix_shared_archive(path))
+    })
+}
+
+fn is_aix_shared_archive(path: &Path) -> bool {
+    // FIXME(#133268): reading the entire file as &[u8] into memory seems excessive
+    // look into either mmap it or use the ReadCache
+    let data = match fs::read(path) {
+        Ok(data) => data,
+        Err(_) => return false,
+    };
+    let file = match ArchiveFile::parse(&*data) {
+        Ok(file) => file,
+        Err(_) => return false,
+    };
+
+    file.members()
+        .filter_map(Result::ok)
+        .any(|entry| String::from_utf8_lossy(entry.name()).contains(".so"))
 }
 
 /// Returns `true` if the file name given looks like a debug info file
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 5690d8edea6..b874f71832d 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -116,7 +116,7 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
 
-  if [ "$DEPLOY_ALT" != "" ]; then
+  if [ "$DEPLOY_ALT" != "" ] && isLinux; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level=2"
   else
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1"
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index f38d34fccd4..0942b5ebfee 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -179,7 +179,7 @@ This informs `rustc` of the name of your crate.
 <a id="option-edition"></a>
 ## `--edition`: specify the edition to use
 
-This flag takes a value of `2015`, `2018` or `2021`. The default is `2015`. More
+This flag takes a value of `2015`, `2018`,`2021`, or `2024`. The default is `2015`. More
 information about editions may be found in the [edition guide].
 
 [edition guide]: ../edition-guide/introduction.html
diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
index c93893b5ada..e02c26bd42b 100644
--- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md
+++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
@@ -360,7 +360,7 @@ are added.
 # fn foo() {}
 ```
 
-`edition2015`, `edition2018` and `edition2021` tell `rustdoc`
+`edition2015`, `edition2018`, `edition2021`, and `edition2024` tell `rustdoc`
 that the code sample should be compiled using the respective edition of Rust.
 
 ```rust
diff --git a/src/doc/unstable-book/src/language-features/asm-goto.md b/src/doc/unstable-book/src/language-features/asm-goto.md
index d72eb7c0c6e..823118bcae1 100644
--- a/src/doc/unstable-book/src/language-features/asm-goto.md
+++ b/src/doc/unstable-book/src/language-features/asm-goto.md
@@ -21,7 +21,9 @@ unsafe {
 }
 ```
 
-The block must have unit type or diverge.
+The block must have unit type or diverge. The block starts a new safety context,
+so despite outer `unsafe`, you need extra unsafe to perform unsafe operations
+within `label <block>`.
 
 When `label <block>` is used together with `noreturn` option, it means that the
 assembly will not fallthrough. It's allowed to jump to a label within the
diff --git a/src/llvm-project b/src/llvm-project
-Subproject b35599be758613448201a49f4b8c7ebfba5558a
+Subproject 104d0d16c3c7c3fef2435fef6efb2d57b70fff7
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 abadca71400..345c46f944a 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
@@ -233,6 +233,7 @@ fn check_statement<'tcx>(
         | StatementKind::PlaceMention(..)
         | StatementKind::Coverage(..)
         | StatementKind::ConstEvalCounter
+        | StatementKind::BackwardIncompatibleDropHint { .. }
         | StatementKind::Nop => Ok(()),
     }
 }
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index 31b18c3dc10..420579372ac 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -45,21 +45,20 @@ pub struct PackageMetadata {
 
 /// Use `cargo metadata` and `cargo vendor` to get a list of dependencies and their license data.
 ///
-/// This will involve running `cargo vendor` into `${BUILD}/vendor` so we can
+/// This will involve running `cargo vendor` into `vendor_path` so we can
 /// grab the license files.
 ///
 /// Any dependency with a path beginning with `root_path` is ignored, as we
 /// assume `reuse` has covered it already.
 pub fn get_metadata_and_notices(
     cargo: &Path,
-    dest: &Path,
+    vendor_path: &Path,
     root_path: &Path,
     manifest_paths: &[&Path],
 ) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
     let mut output = get_metadata(cargo, root_path, manifest_paths)?;
 
     // Now do a cargo-vendor and grab everything
-    let vendor_path = dest.join("vendor");
     println!("Vendoring deps into {}...", vendor_path.display());
     run_cargo_vendor(cargo, &vendor_path, manifest_paths)?;
 
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index afa75d0d671..f9d96b59462 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -6,13 +6,6 @@ use rinja::Template;
 
 mod cargo_metadata;
 
-#[derive(Template)]
-#[template(path = "COPYRIGHT.html")]
-struct CopyrightTemplate {
-    in_tree: Node,
-    dependencies: BTreeMap<cargo_metadata::Package, cargo_metadata::PackageMetadata>,
-}
-
 /// The entry point to the binary.
 ///
 /// You should probably let `bootstrap` execute this program instead of running it directly.
@@ -20,49 +13,89 @@ struct CopyrightTemplate {
 /// Run `x.py run generate-copyright`
 fn main() -> Result<(), Error> {
     let dest_file = env_path("DEST")?;
+    let libstd_dest_file = env_path("DEST_LIBSTD")?;
     let out_dir = env_path("OUT_DIR")?;
     let cargo = env_path("CARGO")?;
     let license_metadata = env_path("LICENSE_METADATA")?;
 
-    let collected_tree_metadata: Metadata =
-        serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
-
     let root_path = std::path::absolute(".")?;
-    let workspace_paths = [
-        Path::new("./Cargo.toml"),
-        Path::new("./src/tools/cargo/Cargo.toml"),
-        Path::new("./library/Cargo.toml"),
-    ];
-    let mut collected_cargo_metadata =
-        cargo_metadata::get_metadata_and_notices(&cargo, &out_dir, &root_path, &workspace_paths)?;
 
-    let stdlib_set =
-        cargo_metadata::get_metadata(&cargo, &root_path, &[Path::new("./library/std/Cargo.toml")])?;
+    // Scan Cargo dependencies
+    let mut collected_cargo_metadata =
+        cargo_metadata::get_metadata_and_notices(&cargo, &out_dir.join("vendor"), &root_path, &[
+            Path::new("./Cargo.toml"),
+            Path::new("./src/tools/cargo/Cargo.toml"),
+            Path::new("./library/Cargo.toml"),
+        ])?;
+
+    let library_collected_cargo_metadata = cargo_metadata::get_metadata_and_notices(
+        &cargo,
+        &out_dir.join("library-vendor"),
+        &root_path,
+        &[Path::new("./library/Cargo.toml")],
+    )?;
 
     for (key, value) in collected_cargo_metadata.iter_mut() {
-        value.is_in_libstd = Some(stdlib_set.contains_key(key));
+        value.is_in_libstd = Some(library_collected_cargo_metadata.contains_key(key));
     }
 
+    // Load JSON output by reuse
+    let collected_tree_metadata: Metadata =
+        serde_json::from_slice(&std::fs::read(&license_metadata)?)?;
+
+    // Find libstd sub-set
+    let library_collected_tree_metadata = Metadata {
+        files: collected_tree_metadata
+            .files
+            .trim_clone(&Path::new("./library"), &Path::new("."))
+            .unwrap(),
+    };
+
+    // Output main file
     let template = CopyrightTemplate {
         in_tree: collected_tree_metadata.files,
         dependencies: collected_cargo_metadata,
     };
-
     let output = template.render()?;
-
     std::fs::write(&dest_file, output)?;
 
+    // Output libstd subset file
+    let template = LibraryCopyrightTemplate {
+        in_tree: library_collected_tree_metadata.files,
+        dependencies: library_collected_cargo_metadata,
+    };
+    let output = template.render()?;
+    std::fs::write(&libstd_dest_file, output)?;
+
     Ok(())
 }
 
+/// The HTML template for the toolchain copyright file
+#[derive(Template)]
+#[template(path = "COPYRIGHT.html")]
+struct CopyrightTemplate {
+    in_tree: Node,
+    dependencies: BTreeMap<cargo_metadata::Package, cargo_metadata::PackageMetadata>,
+}
+
+/// The HTML template for the library copyright file
+#[derive(Template)]
+#[template(path = "COPYRIGHT-library.html")]
+struct LibraryCopyrightTemplate {
+    in_tree: Node,
+    dependencies: BTreeMap<cargo_metadata::Package, cargo_metadata::PackageMetadata>,
+}
+
 /// Describes a tree of metadata for our filesystem tree
-#[derive(serde::Deserialize)]
+///
+/// Must match the JSON emitted by the `CollectLicenseMetadata` bootstrap tool.
+#[derive(serde::Deserialize, Clone, Debug, PartialEq, Eq)]
 struct Metadata {
     files: Node,
 }
 
 /// Describes one node in our metadata tree
-#[derive(serde::Deserialize, rinja::Template)]
+#[derive(serde::Deserialize, rinja::Template, Clone, Debug, PartialEq, Eq)]
 #[serde(rename_all = "kebab-case", tag = "type")]
 #[template(path = "Node.html")]
 pub(crate) enum Node {
@@ -72,8 +105,74 @@ pub(crate) enum Node {
     Group { files: Vec<String>, directories: Vec<String>, license: License },
 }
 
+impl Node {
+    /// Clone, this node, but only if the path to the item is within the match path
+    fn trim_clone(&self, match_path: &Path, parent_path: &Path) -> Option<Node> {
+        match self {
+            Node::Root { children } => {
+                let mut filtered_children = Vec::new();
+                for node in children {
+                    if let Some(child_node) = node.trim_clone(match_path, parent_path) {
+                        filtered_children.push(child_node);
+                    }
+                }
+                if filtered_children.is_empty() {
+                    None
+                } else {
+                    Some(Node::Root { children: filtered_children })
+                }
+            }
+            Node::Directory { name, children, license } => {
+                let child_name = parent_path.join(name);
+                if !(child_name.starts_with(match_path) || match_path.starts_with(&child_name)) {
+                    return None;
+                }
+                let mut filtered_children = Vec::new();
+                for node in children {
+                    if let Some(child_node) = node.trim_clone(match_path, &child_name) {
+                        filtered_children.push(child_node);
+                    }
+                }
+                Some(Node::Directory {
+                    name: name.clone(),
+                    children: filtered_children,
+                    license: license.clone(),
+                })
+            }
+            Node::File { name, license } => {
+                let child_name = parent_path.join(name);
+                if !(child_name.starts_with(match_path) || match_path.starts_with(&child_name)) {
+                    return None;
+                }
+                Some(Node::File { name: name.clone(), license: license.clone() })
+            }
+            Node::Group { files, directories, license } => {
+                let mut filtered_child_files = Vec::new();
+                for child in files {
+                    let child_name = parent_path.join(child);
+                    if child_name.starts_with(match_path) || match_path.starts_with(&child_name) {
+                        filtered_child_files.push(child.clone());
+                    }
+                }
+                let mut filtered_child_dirs = Vec::new();
+                for child in directories {
+                    let child_name = parent_path.join(child);
+                    if child_name.starts_with(match_path) || match_path.starts_with(&child_name) {
+                        filtered_child_dirs.push(child.clone());
+                    }
+                }
+                Some(Node::Group {
+                    files: filtered_child_files,
+                    directories: filtered_child_dirs,
+                    license: license.clone(),
+                })
+            }
+        }
+    }
+}
+
 /// A License has an SPDX license name and a list of copyright holders.
-#[derive(serde::Deserialize)]
+#[derive(serde::Deserialize, Clone, Debug, PartialEq, Eq)]
 struct License {
     spdx: String,
     copyright: Vec<String>,
diff --git a/src/tools/generate-copyright/templates/COPYRIGHT-library.html b/src/tools/generate-copyright/templates/COPYRIGHT-library.html
new file mode 100644
index 00000000000..2c1eba741db
--- /dev/null
+++ b/src/tools/generate-copyright/templates/COPYRIGHT-library.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Copyright notices for The Rust Standard Library</title>
+</head>
+<body>
+
+<h1>Copyright notices for The Rust Standard Library</h1>
+
+<p>This file describes the copyright and licensing information for the Rust
+Standard Library source code within The Rust Project git tree, and the
+third-party dependencies used when building the Rust Standard Library.</p>
+
+<h2>Table of Contents</h2>
+<ul>
+    <li><a href="#in-tree-files">In-tree files</a></li>
+    <li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
+</ul>
+
+<h2 id="in-tree-files">In-tree files</h2>
+
+<p>The following licenses cover the in-tree source files that were used in this
+release:</p>
+
+{{ in_tree|safe }}
+
+<h2 id="out-of-tree-dependencies">Out-of-tree dependencies</h2>
+
+<p>The following licenses cover the out-of-tree crates that were used in the
+Rust Standard Library in this release:</p>
+
+{% for (key, value) in dependencies %}
+    <h3>📦 {{key.name}}-{{key.version}}</h3>
+    <p><b>URL:</b> <a href="https://crates.io/crates/{{ key.name }}/{{ key.version }}">https://crates.io/crates/{{ key.name }}/{{ key.version }}</a></p>
+    <p><b>Authors:</b> {{ value.authors|join(", ") }}</p>
+    <p><b>License:</b> {{ value.license }}</p>
+    {% let len = value.notices.len() %}
+    {% if len > 0 %}
+        <p><b>Notices:</b>
+        {% for (notice_name, notice_text) in value.notices %}
+            <details>
+                <summary><code>{{ notice_name }}</code></summary>
+                <pre>
+{{ notice_text }}
+                </pre>
+            </details>
+        {% endfor %}
+        </p>
+    {% endif %}
+{% endfor %}
+</body>
+</html>
\ No newline at end of file
diff --git a/src/tools/miri/.cargo/config.toml b/src/tools/miri/.cargo/config.toml
deleted file mode 100644
index 42e7c2c4818..00000000000
--- a/src/tools/miri/.cargo/config.toml
+++ /dev/null
@@ -1,9 +0,0 @@
-[unstable]
-profile-rustflags = true
-
-# Add back the containing directory of the packages we have to refer to using --manifest-path.
-# Per-package profiles avoid adding this to build dependencies.
-[profile.dev.package."cargo-miri"]
-rustflags = ["--remap-path-prefix", "=cargo-miri"]
-[profile.dev.package."miri-script"]
-rustflags = ["--remap-path-prefix", "=miri-script"]
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index a73fefaaf34..9a683ae68fd 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -548,6 +548,7 @@ Definite bugs found:
 * [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138)
 * [Occasional memory leak in `std::mpsc` channels](https://github.com/rust-lang/rust/issues/121582) (original code in [crossbeam](https://github.com/crossbeam-rs/crossbeam/pull/1084))
 * [Weak-memory-induced memory leak in Windows thread-local storage](https://github.com/rust-lang/rust/pull/124281)
+* [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo)
 
 Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
 
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index 5d07ad9e249..ac1a7211c4e 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -1,13 +1,15 @@
 #!/usr/bin/env bash
 set -e
 # We want to call the binary directly, so we need to know where it ends up.
-MIRI_SCRIPT_TARGET_DIR="$(dirname "$0")"/miri-script/target
+ROOT_DIR="$(dirname "$0")"
+MIRI_SCRIPT_TARGET_DIR="$ROOT_DIR"/miri-script/target
 # If stdout is not a terminal and we are not on CI, assume that we are being invoked by RA, and use JSON output.
 if ! [ -t 1 ] && [ -z "$CI" ]; then
   MESSAGE_FORMAT="--message-format=json"
 fi
-# We need a nightly toolchain, for the `profile-rustflags` cargo feature.
-cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml \
+# We need a nightly toolchain, for `-Zroot-dir`.
+cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
+  -Zroot-dir="$ROOT_DIR" \
   -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" $MESSAGE_FORMAT || \
   ( echo "Failed to build miri-script. Is the 'nightly' toolchain installed?"; exit 1 )
 # Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index e6e85747d4d..cf6529d8373 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -105,7 +105,7 @@ impl MiriEnv {
 
         // Get extra flags for cargo.
         let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default();
-        let cargo_extra_flags = flagsplit(&cargo_extra_flags);
+        let mut cargo_extra_flags = flagsplit(&cargo_extra_flags);
         if cargo_extra_flags.iter().any(|a| a == "--release" || a.starts_with("--profile")) {
             // This makes binaries end up in different paths, let's not do that.
             eprintln!(
@@ -113,6 +113,8 @@ impl MiriEnv {
             );
             std::process::exit(1);
         }
+        // Also set `-Zroot-dir` for cargo, to print diagnostics relative to the miri dir.
+        cargo_extra_flags.push(format!("-Zroot-dir={}", miri_dir.display()));
 
         Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags, libdir })
     }
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index bec28af6257..effed0cd180 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-668959740f97e7a22ae340742886d330ab63950f
+2d0ea7956c45de6e421fd579e2ded27be405dec6
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 9627447b342..a855603eeb3 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -12,6 +12,7 @@ use std::{cmp, mem};
 use rustc_abi::{BackendRepr, Size};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::{Mutability, RetagKind};
+use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::{self, Ty};
 
 use self::diagnostics::{RetagCause, RetagInfo};
@@ -70,7 +71,7 @@ impl NewPermission {
                         access: None,
                         protector: None,
                     }
-                } else if pointee.is_unpin(*cx.tcx, cx.typing_env) {
+                } else if pointee.is_unpin(*cx.tcx, cx.typing_env()) {
                     // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`.
                     NewPermission::Uniform {
                         perm: Permission::Unique,
@@ -128,7 +129,7 @@ impl NewPermission {
     fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self {
         // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
         let pointee = ty.builtin_deref(true).unwrap();
-        if pointee.is_unpin(*cx.tcx, cx.typing_env) {
+        if pointee.is_unpin(*cx.tcx, cx.typing_env()) {
             // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
             // a weak protector).
             NewPermission::Uniform {
@@ -607,7 +608,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                 match new_perm {
                     NewPermission::Uniform { perm, .. } =>
                         write!(kind_str, "{perm:?} permission").unwrap(),
-                    NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env) =>
+                    NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env()) =>
                         write!(kind_str, "{freeze_perm:?} permission").unwrap(),
                     NewPermission::FreezeSensitive { freeze_perm, nonfreeze_perm, .. }  =>
                         write!(kind_str, "{freeze_perm:?}/{nonfreeze_perm:?} permission for frozen/non-frozen parts").unwrap(),
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 61a2e2bc8d9..8469744bbc4 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -1,5 +1,6 @@
 use rustc_abi::{BackendRepr, Size};
 use rustc_middle::mir::{Mutability, RetagKind};
+use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::def_id::DefId;
 
@@ -131,8 +132,8 @@ impl<'tcx> NewPermission {
         kind: RetagKind,
         cx: &crate::MiriInterpCx<'tcx>,
     ) -> Option<Self> {
-        let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env);
-        let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env);
+        let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
+        let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env());
         let is_protected = kind == RetagKind::FnEntry;
         // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
         // interior mutability and protectors interact poorly.
@@ -163,10 +164,10 @@ impl<'tcx> NewPermission {
         zero_size: bool,
     ) -> Option<Self> {
         let pointee = ty.builtin_deref(true).unwrap();
-        pointee.is_unpin(*cx.tcx, cx.typing_env).then_some(()).map(|()| {
+        pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| {
             // Regular `Unpin` box, give it `noalias` but only a weak protector
             // because it is valid to deallocate it within the function.
-            let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env);
+            let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env());
             let protected = kind == RetagKind::FnEntry;
             let initial_state = Permission::new_reserved(ty_is_freeze, protected);
             Self {
@@ -520,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Note: if we were to inline `new_reserved` below we would find out that
         // `ty_is_freeze` is eventually unused because it appears in a `ty_is_freeze || true`.
         // We are nevertheless including it here for clarity.
-        let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env);
+        let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env());
         // Retag it. With protection! That is the entire point.
         let new_perm = NewPermission {
             initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true),
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index 02e8261a6ed..ef4034cc0c1 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -1,6 +1,7 @@
 use std::cell::RefCell;
 use std::collections::VecDeque;
 use std::collections::hash_map::Entry;
+use std::default::Default;
 use std::ops::Not;
 use std::rc::Rc;
 use std::time::Duration;
@@ -46,8 +47,6 @@ macro_rules! declare_id {
 }
 pub(super) use declare_id;
 
-declare_id!(MutexId);
-
 /// The mutex state.
 #[derive(Default, Debug)]
 struct Mutex {
@@ -61,6 +60,21 @@ struct Mutex {
     clock: VClock,
 }
 
+#[derive(Default, Clone, Debug)]
+pub struct MutexRef(Rc<RefCell<Mutex>>);
+
+impl MutexRef {
+    fn new() -> Self {
+        MutexRef(Rc::new(RefCell::new(Mutex::default())))
+    }
+}
+
+impl VisitProvenance for MutexRef {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        // Mutex contains no provenance.
+    }
+}
+
 declare_id!(RwLockId);
 
 /// The read-write lock state.
@@ -144,7 +158,6 @@ struct FutexWaiter {
 /// The state of all synchronization objects.
 #[derive(Default, Debug)]
 pub struct SynchronizationObjects {
-    mutexes: IndexVec<MutexId, Mutex>,
     rwlocks: IndexVec<RwLockId, RwLock>,
     condvars: IndexVec<CondvarId, Condvar>,
     pub(super) init_onces: IndexVec<InitOnceId, InitOnce>,
@@ -155,17 +168,17 @@ impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn condvar_reacquire_mutex(
         &mut self,
-        mutex: MutexId,
+        mutex_ref: &MutexRef,
         retval: Scalar,
         dest: MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        if this.mutex_is_locked(mutex) {
-            assert_ne!(this.mutex_get_owner(mutex), this.active_thread());
-            this.mutex_enqueue_and_block(mutex, Some((retval, dest)));
+        if this.mutex_is_locked(mutex_ref) {
+            assert_ne!(this.mutex_get_owner(mutex_ref), this.active_thread());
+            this.mutex_enqueue_and_block(mutex_ref, Some((retval, dest)));
         } else {
             // We can have it right now!
-            this.mutex_lock(mutex);
+            this.mutex_lock(mutex_ref);
             // Don't forget to write the return value.
             this.write_scalar(retval, &dest)?;
         }
@@ -174,10 +187,9 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 }
 
 impl SynchronizationObjects {
-    pub fn mutex_create(&mut self) -> MutexId {
-        self.mutexes.push(Default::default())
+    pub fn mutex_create(&mut self) -> MutexRef {
+        MutexRef::new()
     }
-
     pub fn rwlock_create(&mut self) -> RwLockId {
         self.rwlocks.push(Default::default())
     }
@@ -209,12 +221,16 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
 pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// Helper for lazily initialized `alloc_extra.sync` data:
     /// this forces an immediate init.
-    fn lazy_sync_init<T: 'static + Copy>(
-        &mut self,
+    /// Return a reference to the data in the machine state.
+    fn lazy_sync_init<'a, T: 'static>(
+        &'a mut self,
         primitive: &MPlaceTy<'tcx>,
         init_offset: Size,
         data: T,
-    ) -> InterpResult<'tcx> {
+    ) -> InterpResult<'tcx, &'a T>
+    where
+        'tcx: 'a,
+    {
         let this = self.eval_context_mut();
 
         let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
@@ -227,7 +243,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             &init_field,
             AtomicWriteOrd::Relaxed,
         )?;
-        interp_ok(())
+        interp_ok(this.get_alloc_extra(alloc)?.get_sync::<T>(offset).unwrap())
     }
 
     /// Helper for lazily initialized `alloc_extra.sync` data:
@@ -235,13 +251,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// - If yes, fetches the data from `alloc_extra.sync`, or calls `missing_data` if that fails
     ///   and stores that in `alloc_extra.sync`.
     /// - Otherwise, calls `new_data` to initialize the primitive.
-    fn lazy_sync_get_data<T: 'static + Copy>(
-        &mut self,
+    ///
+    /// Return a reference to the data in the machine state.
+    fn lazy_sync_get_data<'a, T: 'static>(
+        &'a mut self,
         primitive: &MPlaceTy<'tcx>,
         init_offset: Size,
         missing_data: impl FnOnce() -> InterpResult<'tcx, T>,
         new_data: impl FnOnce(&mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, T>,
-    ) -> InterpResult<'tcx, T> {
+    ) -> InterpResult<'tcx, &'a T>
+    where
+        'tcx: 'a,
+    {
         let this = self.eval_context_mut();
 
         // Check if this is already initialized. Needs to be atomic because we can race with another
@@ -265,17 +286,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // or else it has been moved illegally.
             let (alloc, offset, _) = this.ptr_get_alloc_id(primitive.ptr(), 0)?;
             let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc)?;
-            if let Some(data) = alloc_extra.get_sync::<T>(offset) {
-                interp_ok(*data)
-            } else {
+            // Due to borrow checker reasons, we have to do the lookup twice.
+            if alloc_extra.get_sync::<T>(offset).is_none() {
                 let data = missing_data()?;
                 alloc_extra.sync.insert(offset, Box::new(data));
-                interp_ok(data)
             }
+            interp_ok(alloc_extra.get_sync::<T>(offset).unwrap())
         } else {
             let data = new_data(this)?;
-            this.lazy_sync_init(primitive, init_offset, data)?;
-            interp_ok(data)
+            this.lazy_sync_init(primitive, init_offset, data)
         }
     }
 
@@ -311,23 +330,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
     #[inline]
     /// Get the id of the thread that currently owns this lock.
-    fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId {
-        let this = self.eval_context_ref();
-        this.machine.sync.mutexes[id].owner.unwrap()
+    fn mutex_get_owner(&self, mutex_ref: &MutexRef) -> ThreadId {
+        mutex_ref.0.borrow().owner.unwrap()
     }
 
     #[inline]
     /// Check if locked.
-    fn mutex_is_locked(&self, id: MutexId) -> bool {
-        let this = self.eval_context_ref();
-        this.machine.sync.mutexes[id].owner.is_some()
+    fn mutex_is_locked(&self, mutex_ref: &MutexRef) -> bool {
+        mutex_ref.0.borrow().owner.is_some()
     }
 
     /// Lock by setting the mutex owner and increasing the lock count.
-    fn mutex_lock(&mut self, id: MutexId) {
+    fn mutex_lock(&mut self, mutex_ref: &MutexRef) {
         let this = self.eval_context_mut();
         let thread = this.active_thread();
-        let mutex = &mut this.machine.sync.mutexes[id];
+        let mut mutex = mutex_ref.0.borrow_mut();
         if let Some(current_owner) = mutex.owner {
             assert_eq!(thread, current_owner, "mutex already locked by another thread");
             assert!(
@@ -347,9 +364,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// count. If the lock count reaches 0, release the lock and potentially
     /// give to a new owner. If the lock was not locked by the current thread,
     /// return `None`.
-    fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<usize>> {
+    fn mutex_unlock(&mut self, mutex_ref: &MutexRef) -> InterpResult<'tcx, Option<usize>> {
         let this = self.eval_context_mut();
-        let mutex = &mut this.machine.sync.mutexes[id];
+        let mut mutex = mutex_ref.0.borrow_mut();
         interp_ok(if let Some(current_owner) = mutex.owner {
             // Mutex is locked.
             if current_owner != this.machine.threads.active_thread() {
@@ -367,8 +384,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         mutex.clock.clone_from(clock)
                     });
                 }
-                if let Some(thread) = this.machine.sync.mutexes[id].queue.pop_front() {
-                    this.unblock_thread(thread, BlockReason::Mutex(id))?;
+                let thread_id = mutex.queue.pop_front();
+                // We need to drop our mutex borrow before unblock_thread
+                // because it will be borrowed again in the unblock callback.
+                drop(mutex);
+                if thread_id.is_some() {
+                    this.unblock_thread(thread_id.unwrap(), BlockReason::Mutex)?;
                 }
             }
             Some(old_lock_count)
@@ -385,24 +406,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     #[inline]
     fn mutex_enqueue_and_block(
         &mut self,
-        id: MutexId,
+        mutex_ref: &MutexRef,
         retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
     ) {
         let this = self.eval_context_mut();
-        assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
+        assert!(this.mutex_is_locked(mutex_ref), "queuing on unlocked mutex");
         let thread = this.active_thread();
-        this.machine.sync.mutexes[id].queue.push_back(thread);
+        mutex_ref.0.borrow_mut().queue.push_back(thread);
+        let mutex_ref = mutex_ref.clone();
         this.block_thread(
-            BlockReason::Mutex(id),
+            BlockReason::Mutex,
             None,
             callback!(
                 @capture<'tcx> {
-                    id: MutexId,
+                    mutex_ref: MutexRef,
                     retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
                 }
                 @unblock = |this| {
-                    assert!(!this.mutex_is_locked(id));
-                    this.mutex_lock(id);
+                    assert!(!this.mutex_is_locked(&mutex_ref));
+                    this.mutex_lock(&mutex_ref);
 
                     if let Some((retval, dest)) = retval_dest {
                         this.write_scalar(retval, &dest)?;
@@ -623,14 +645,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn condvar_wait(
         &mut self,
         condvar: CondvarId,
-        mutex: MutexId,
+        mutex_ref: MutexRef,
         timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>,
         retval_succ: Scalar,
         retval_timeout: Scalar,
         dest: MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        if let Some(old_locked_count) = this.mutex_unlock(mutex)? {
+        if let Some(old_locked_count) = this.mutex_unlock(&mutex_ref)? {
             if old_locked_count != 1 {
                 throw_unsup_format!(
                     "awaiting a condvar on a mutex acquired multiple times is not supported"
@@ -650,7 +672,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             callback!(
                 @capture<'tcx> {
                     condvar: CondvarId,
-                    mutex: MutexId,
+                    mutex_ref: MutexRef,
                     retval_succ: Scalar,
                     retval_timeout: Scalar,
                     dest: MPlaceTy<'tcx>,
@@ -665,7 +687,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     }
                     // Try to acquire the mutex.
                     // The timeout only applies to the first wait (until the signal), not for mutex acquisition.
-                    this.condvar_reacquire_mutex(mutex, retval_succ, dest)
+                    this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
                 }
                 @timeout = |this| {
                     // We have to remove the waiter from the queue again.
@@ -673,7 +695,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let waiters = &mut this.machine.sync.condvars[condvar].waiters;
                     waiters.retain(|waiter| *waiter != thread);
                     // Now get back the lock.
-                    this.condvar_reacquire_mutex(mutex, retval_timeout, dest)
+                    this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
                 }
             ),
         );
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index e6a3ae897c2..59e2fdd4285 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -113,6 +113,11 @@ impl ThreadId {
         self.0
     }
 
+    /// Create a new thread id from a `u32` without checking if this thread exists.
+    pub fn new_unchecked(id: u32) -> Self {
+        Self(id)
+    }
+
     pub const MAIN_THREAD: ThreadId = ThreadId(0);
 }
 
@@ -141,7 +146,7 @@ pub enum BlockReason {
     /// Waiting for time to pass.
     Sleep,
     /// Blocked on a mutex.
-    Mutex(MutexId),
+    Mutex,
     /// Blocked on a condition variable.
     Condvar(CondvarId),
     /// Blocked on a reader-writer lock.
@@ -152,6 +157,8 @@ pub enum BlockReason {
     InitOnce(InitOnceId),
     /// Blocked on epoll.
     Epoll,
+    /// Blocked on eventfd.
+    Eventfd,
 }
 
 /// The state of a thread.
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 63591474120..41b7be37c37 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -195,7 +195,7 @@ pub fn prune_stacktrace<'tcx>(
                 // This len check ensures that we don't somehow remove every frame, as doing so breaks
                 // the primary error message.
                 while stacktrace.len() > 1
-                    && stacktrace.last().map_or(false, |frame| !machine.is_local(frame))
+                    && stacktrace.last().is_some_and(|frame| !machine.is_local(frame))
                 {
                     stacktrace.pop();
                 }
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 85591a0b370..1df1d08802a 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -270,12 +270,8 @@ pub fn create_ecx<'tcx>(
 ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
     let typing_env = ty::TypingEnv::fully_monomorphized();
     let layout_cx = LayoutCx::new(tcx, typing_env);
-    let mut ecx = InterpCx::new(
-        tcx,
-        rustc_span::DUMMY_SP,
-        typing_env,
-        MiriMachine::new(config, layout_cx)
-    );
+    let mut ecx =
+        InterpCx::new(tcx, rustc_span::DUMMY_SP, typing_env, MiriMachine::new(config, layout_cx));
 
     // Some parts of initialization require a full `InterpCx`.
     MiriMachine::late_init(&mut ecx, config, {
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 4b34f1686a0..b57ce4e070c 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -116,8 +116,7 @@ pub fn resolve_path<'tcx>(
 /// Gets the layout of a type at a path.
 #[track_caller]
 pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLayout<'tcx> {
-    let ty = resolve_path(cx.tcx(), path, Namespace::TypeNS)
-        .ty(cx.tcx(), cx.typing_env());
+    let ty = resolve_path(cx.tcx(), path, Namespace::TypeNS).ty(cx.tcx(), cx.typing_env());
     cx.layout_of(ty).to_result().ok().unwrap()
 }
 
@@ -1009,7 +1008,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_ref();
 
         fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>(
-            this: &MiriInterpCx<'tcx>,
+            ecx: &MiriInterpCx<'tcx>,
             src: F,
             cast_to: TyAndLayout<'tcx>,
             round: rustc_apfloat::Round,
@@ -1029,7 +1028,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Nothing else
                 _ =>
                     span_bug!(
-                        this.cur_span(),
+                        ecx.cur_span(),
                         "attempted float-to-int conversion with non-int output type {}",
                         cast_to.ty,
                     ),
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 272dca1594e..9eebbc5d363 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -218,20 +218,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             => {
                 let [f] = check_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
-                // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                let f_host = f.to_host();
+                // Using host floats except for sqrt (but it's fine, these operations do not have
+                // guaranteed precision).
                 let res = match intrinsic_name {
-                    "sinf32" => f_host.sin(),
-                    "cosf32" => f_host.cos(),
-                    "sqrtf32" => f_host.sqrt(), // FIXME Using host floats, this should use full-precision soft-floats
-                    "expf32" => f_host.exp(),
-                    "exp2f32" => f_host.exp2(),
-                    "logf32" => f_host.ln(),
-                    "log10f32" => f_host.log10(),
-                    "log2f32" => f_host.log2(),
+                    "sinf32" => f.to_host().sin().to_soft(),
+                    "cosf32" => f.to_host().cos().to_soft(),
+                    "sqrtf32" => math::sqrt(f),
+                    "expf32" => f.to_host().exp().to_soft(),
+                    "exp2f32" => f.to_host().exp2().to_soft(),
+                    "logf32" => f.to_host().ln().to_soft(),
+                    "log10f32" => f.to_host().log10().to_soft(),
+                    "log2f32" => f.to_host().log2().to_soft(),
                     _ => bug!(),
                 };
-                let res = res.to_soft();
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
@@ -247,20 +246,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             => {
                 let [f] = check_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
-                // Using host floats (but it's fine, these operations do not have guaranteed precision).
-                let f_host = f.to_host();
+                // Using host floats except for sqrt (but it's fine, these operations do not have
+                // guaranteed precision).
                 let res = match intrinsic_name {
-                    "sinf64" => f_host.sin(),
-                    "cosf64" => f_host.cos(),
-                    "sqrtf64" => f_host.sqrt(), // FIXME Using host floats, this should use full-precision soft-floats
-                    "expf64" => f_host.exp(),
-                    "exp2f64" => f_host.exp2(),
-                    "logf64" => f_host.ln(),
-                    "log10f64" => f_host.log10(),
-                    "log2f64" => f_host.log2(),
+                    "sinf64" => f.to_host().sin().to_soft(),
+                    "cosf64" => f.to_host().cos().to_soft(),
+                    "sqrtf64" => math::sqrt(f),
+                    "expf64" => f.to_host().exp().to_soft(),
+                    "exp2f64" => f.to_host().exp2().to_soft(),
+                    "logf64" => f.to_host().ln().to_soft(),
+                    "log10f64" => f.to_host().log10().to_soft(),
+                    "log2f64" => f.to_host().log2().to_soft(),
                     _ => bug!(),
                 };
-                let res = res.to_soft();
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index d5c417e7231..075b6f35e0e 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -104,42 +104,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             let ty::Float(float_ty) = op.layout.ty.kind() else {
                                 span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
                             };
-                            // Using host floats (but it's fine, these operations do not have guaranteed precision).
+                            // Using host floats except for sqrt (but it's fine, these operations do not
+                            // have guaranteed precision).
                             match float_ty {
                                 FloatTy::F16 => unimplemented!("f16_f128"),
                                 FloatTy::F32 => {
                                     let f = op.to_scalar().to_f32()?;
-                                    let f_host = f.to_host();
                                     let res = match host_op {
-                                        "fsqrt" => f_host.sqrt(), // FIXME Using host floats, this should use full-precision soft-floats
-                                        "fsin" => f_host.sin(),
-                                        "fcos" => f_host.cos(),
-                                        "fexp" => f_host.exp(),
-                                        "fexp2" => f_host.exp2(),
-                                        "flog" => f_host.ln(),
-                                        "flog2" => f_host.log2(),
-                                        "flog10" => f_host.log10(),
+                                        "fsqrt" => math::sqrt(f),
+                                        "fsin" => f.to_host().sin().to_soft(),
+                                        "fcos" => f.to_host().cos().to_soft(),
+                                        "fexp" => f.to_host().exp().to_soft(),
+                                        "fexp2" => f.to_host().exp2().to_soft(),
+                                        "flog" => f.to_host().ln().to_soft(),
+                                        "flog2" => f.to_host().log2().to_soft(),
+                                        "flog10" => f.to_host().log10().to_soft(),
                                         _ => bug!(),
                                     };
-                                    let res = res.to_soft();
                                     let res = this.adjust_nan(res, &[f]);
                                     Scalar::from(res)
                                 }
                                 FloatTy::F64 => {
                                     let f = op.to_scalar().to_f64()?;
-                                    let f_host = f.to_host();
                                     let res = match host_op {
-                                        "fsqrt" => f_host.sqrt(),
-                                        "fsin" => f_host.sin(),
-                                        "fcos" => f_host.cos(),
-                                        "fexp" => f_host.exp(),
-                                        "fexp2" => f_host.exp2(),
-                                        "flog" => f_host.ln(),
-                                        "flog2" => f_host.log2(),
-                                        "flog10" => f_host.log10(),
+                                        "fsqrt" => math::sqrt(f),
+                                        "fsin" => f.to_host().sin().to_soft(),
+                                        "fcos" => f.to_host().cos().to_soft(),
+                                        "fexp" => f.to_host().exp().to_soft(),
+                                        "fexp2" => f.to_host().exp2().to_soft(),
+                                        "flog" => f.to_host().ln().to_soft(),
+                                        "flog2" => f.to_host().log2().to_soft(),
+                                        "flog10" => f.to_host().log10().to_soft(),
                                         _ => bug!(),
                                     };
-                                    let res = res.to_soft();
                                     let res = this.adjust_nan(res, &[f]);
                                     Scalar::from(res)
                                 }
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index f903ccbc25a..85c896563da 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -83,6 +83,7 @@ mod eval;
 mod helpers;
 mod intrinsics;
 mod machine;
+mod math;
 mod mono_hash_map;
 mod operator;
 mod provenance_gc;
@@ -122,7 +123,7 @@ pub use crate::concurrency::data_race::{
 };
 pub use crate::concurrency::init_once::{EvalContextExt as _, InitOnceId};
 pub use crate::concurrency::sync::{
-    CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects,
+    CondvarId, EvalContextExt as _, MutexRef, RwLockId, SynchronizationObjects,
 };
 pub use crate::concurrency::thread::{
     BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 3ab606e5847..814dc6d2b01 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -17,7 +17,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::static_assert_size;
 use rustc_middle::mir;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::{
+    HasTyCtxt, HasTypingEnv, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
+};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::config::InliningThreshold;
 use rustc_span::def_id::{CrateNum, DefId};
@@ -730,20 +732,20 @@ impl<'tcx> MiriMachine<'tcx> {
     }
 
     pub(crate) fn late_init(
-        this: &mut MiriInterpCx<'tcx>,
+        ecx: &mut MiriInterpCx<'tcx>,
         config: &MiriConfig,
         on_main_stack_empty: StackEmptyCallback<'tcx>,
     ) -> InterpResult<'tcx> {
-        EnvVars::init(this, config)?;
-        MiriMachine::init_extern_statics(this)?;
-        ThreadManager::init(this, on_main_stack_empty);
+        EnvVars::init(ecx, config)?;
+        MiriMachine::init_extern_statics(ecx)?;
+        ThreadManager::init(ecx, on_main_stack_empty);
         interp_ok(())
     }
 
-    pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
+    pub(crate) fn add_extern_static(ecx: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
         // This got just allocated, so there definitely is a pointer here.
         let ptr = ptr.into_pointer_or_addr().unwrap();
-        this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
+        ecx.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
     }
 
     pub(crate) fn communicate(&self) -> bool {
@@ -1127,9 +1129,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             };
             let info = ecx.get_alloc_info(alloc_id);
             let def_ty = ecx.tcx.type_of(def_id).instantiate_identity();
-            let extern_decl_layout = ecx.tcx.layout_of(
-                ecx.typing_env.as_query_input(def_ty)
-            ).unwrap();
+            let extern_decl_layout =
+                ecx.tcx.layout_of(ecx.typing_env().as_query_input(def_ty)).unwrap();
             if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align {
                 throw_unsup_format!(
                     "extern static `{link_name}` has been declared as `{krate}::{name}` \
diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs
new file mode 100644
index 00000000000..ed3d2d55678
--- /dev/null
+++ b/src/tools/miri/src/math.rs
@@ -0,0 +1,164 @@
+use rand::Rng as _;
+use rand::distributions::Distribution as _;
+use rustc_apfloat::Float as _;
+use rustc_apfloat::ieee::IeeeFloat;
+
+/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale).
+pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
+    ecx: &mut crate::MiriInterpCx<'_>,
+    val: F,
+    err_scale: i32,
+) -> F {
+    let rng = ecx.machine.rng.get_mut();
+    // Generate a random integer in the range [0, 2^PREC).
+    let dist = rand::distributions::Uniform::new(0, 1 << F::PRECISION);
+    let err = F::from_u128(dist.sample(rng))
+        .value
+        .scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap()));
+    // give it a random sign
+    let err = if rng.gen::<bool>() { -err } else { err };
+    // multiple the value with (1+err)
+    (val * (F::from_u128(1).value + err).value).value
+}
+
+pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFloat<S> {
+    match x.category() {
+        // preserve zero sign
+        rustc_apfloat::Category::Zero => x,
+        // propagate NaN
+        rustc_apfloat::Category::NaN => x,
+        // sqrt of negative number is NaN
+        _ if x.is_negative() => IeeeFloat::NAN,
+        // sqrt(∞) = ∞
+        rustc_apfloat::Category::Infinity => IeeeFloat::INFINITY,
+        rustc_apfloat::Category::Normal => {
+            // Floating point precision, excluding the integer bit
+            let prec = i32::try_from(S::PRECISION).unwrap() - 1;
+
+            // x = 2^(exp - prec) * mant
+            // where mant is an integer with prec+1 bits
+            // mant is a u128, which should be large enough for the largest prec (112 for f128)
+            let mut exp = x.ilogb();
+            let mut mant = x.scalbn(prec - exp).to_u128(128).value;
+
+            if exp % 2 != 0 {
+                // Make exponent even, so it can be divided by 2
+                exp -= 1;
+                mant <<= 1;
+            }
+
+            // Bit-by-bit (base-2 digit-by-digit) sqrt of mant.
+            // mant is treated here as a fixed point number with prec fractional bits.
+            // mant will be shifted left by one bit to have an extra fractional bit, which
+            // will be used to determine the rounding direction.
+
+            // res is the truncated sqrt of mant, where one bit is added at each iteration.
+            let mut res = 0u128;
+            // rem is the remainder with the current res
+            // rem_i = 2^i * ((mant<<1) - res_i^2)
+            // starting with res = 0, rem = mant<<1
+            let mut rem = mant << 1;
+            // s_i = 2*res_i
+            let mut s = 0u128;
+            // d is used to iterate over bits, from high to low (d_i = 2^(-i))
+            let mut d = 1u128 << (prec + 1);
+
+            // For iteration j=i+1, we need to find largest b_j = 0 or 1 such that
+            //  (res_i + b_j * 2^(-j))^2 <= mant<<1
+            // Expanding (a + b)^2 = a^2 + b^2 + 2*a*b:
+            //  res_i^2 + (b_j * 2^(-j))^2 + 2 * res_i * b_j * 2^(-j) <= mant<<1
+            // And rearranging the terms:
+            //  b_j^2 * 2^(-j) + 2 * res_i * b_j <= 2^j * (mant<<1 - res_i^2)
+            //  b_j^2 * 2^(-j) + 2 * res_i * b_j <= rem_i
+
+            while d != 0 {
+                // Probe b_j^2 * 2^(-j) + 2 * res_i * b_j <= rem_i with b_j = 1:
+                // t = 2*res_i + 2^(-j)
+                let t = s + d;
+                if rem >= t {
+                    // b_j should be 1, so make res_j = res_i + 2^(-j) and adjust rem
+                    res += d;
+                    s += d + d;
+                    rem -= t;
+                }
+                // Adjust rem for next iteration
+                rem <<= 1;
+                // Shift iterator
+                d >>= 1;
+            }
+
+            // Remove extra fractional bit from result, rounding to nearest.
+            // If the last bit is 0, then the nearest neighbor is definitely the lower one.
+            // If the last bit is 1, it sounds like this may either be a tie (if there's
+            // infinitely many 0s after this 1), or the nearest neighbor is the upper one.
+            // However, since square roots are either exact or irrational, and an exact root
+            // would lead to the last "extra" bit being 0, we can exclude a tie in this case.
+            // We therefore always round up if the last bit is 1. When the last bit is 0,
+            // adding 1 will not do anything since the shift will discard it.
+            res = (res + 1) >> 1;
+
+            // Build resulting value with res as mantissa and exp/2 as exponent
+            IeeeFloat::from_u128(res).value.scalbn(exp / 2 - prec)
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS};
+
+    use super::sqrt;
+
+    #[test]
+    fn test_sqrt() {
+        #[track_caller]
+        fn test<S: rustc_apfloat::ieee::Semantics>(x: &str, expected: &str) {
+            let x: IeeeFloat<S> = x.parse().unwrap();
+            let expected: IeeeFloat<S> = expected.parse().unwrap();
+            let result = sqrt(x);
+            assert_eq!(result, expected);
+        }
+
+        fn exact_tests<S: rustc_apfloat::ieee::Semantics>() {
+            test::<S>("0", "0");
+            test::<S>("1", "1");
+            test::<S>("1.5625", "1.25");
+            test::<S>("2.25", "1.5");
+            test::<S>("4", "2");
+            test::<S>("5.0625", "2.25");
+            test::<S>("9", "3");
+            test::<S>("16", "4");
+            test::<S>("25", "5");
+            test::<S>("36", "6");
+            test::<S>("49", "7");
+            test::<S>("64", "8");
+            test::<S>("81", "9");
+            test::<S>("100", "10");
+
+            test::<S>("0.5625", "0.75");
+            test::<S>("0.25", "0.5");
+            test::<S>("0.0625", "0.25");
+            test::<S>("0.00390625", "0.0625");
+        }
+
+        exact_tests::<HalfS>();
+        exact_tests::<SingleS>();
+        exact_tests::<DoubleS>();
+        exact_tests::<QuadS>();
+
+        test::<SingleS>("2", "1.4142135");
+        test::<DoubleS>("2", "1.4142135623730951");
+
+        test::<SingleS>("1.1", "1.0488088");
+        test::<DoubleS>("1.1", "1.0488088481701516");
+
+        test::<SingleS>("2.2", "1.4832398");
+        test::<DoubleS>("2.2", "1.4832396974191326");
+
+        test::<SingleS>("1.22101e-40", "1.10499205e-20");
+        test::<DoubleS>("1.22101e-310", "1.1049932126488395e-155");
+
+        test::<SingleS>("3.4028235e38", "1.8446743e19");
+        test::<DoubleS>("1.7976931348623157e308", "1.3407807929942596e154");
+    }
+}
diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs
index 6042a9eb2eb..b3d715db9cd 100644
--- a/src/tools/miri/src/provenance_gc.rs
+++ b/src/tools/miri/src/provenance_gc.rs
@@ -195,10 +195,10 @@ impl LiveAllocs<'_, '_> {
     }
 }
 
-fn remove_unreachable_tags<'tcx>(this: &mut MiriInterpCx<'tcx>, tags: FxHashSet<BorTag>) {
+fn remove_unreachable_tags<'tcx>(ecx: &mut MiriInterpCx<'tcx>, tags: FxHashSet<BorTag>) {
     // Avoid iterating all allocations if there's no borrow tracker anyway.
-    if this.machine.borrow_tracker.is_some() {
-        this.memory.alloc_map().iter(|it| {
+    if ecx.machine.borrow_tracker.is_some() {
+        ecx.memory.alloc_map().iter(|it| {
             for (_id, (_kind, alloc)) in it {
                 alloc.extra.borrow_tracker.as_ref().unwrap().remove_unreachable_tags(&tags);
             }
@@ -206,16 +206,16 @@ fn remove_unreachable_tags<'tcx>(this: &mut MiriInterpCx<'tcx>, tags: FxHashSet<
     }
 }
 
-fn remove_unreachable_allocs<'tcx>(this: &mut MiriInterpCx<'tcx>, allocs: FxHashSet<AllocId>) {
-    let allocs = LiveAllocs { ecx: this, collected: allocs };
-    this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
-    this.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id));
-    this.machine.alloc_addresses.borrow_mut().remove_unreachable_allocs(&allocs);
-    if let Some(borrow_tracker) = &this.machine.borrow_tracker {
+fn remove_unreachable_allocs<'tcx>(ecx: &mut MiriInterpCx<'tcx>, allocs: FxHashSet<AllocId>) {
+    let allocs = LiveAllocs { ecx, collected: allocs };
+    ecx.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
+    ecx.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id));
+    ecx.machine.alloc_addresses.borrow_mut().remove_unreachable_allocs(&allocs);
+    if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
         borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs);
     }
     // Clean up core (non-Miri-specific) state.
-    this.remove_unreachable_allocs(&allocs.collected);
+    ecx.remove_unreachable_allocs(&allocs.collected);
 }
 
 impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs
index 5559ea2750b..f0aebfe1693 100644
--- a/src/tools/miri/src/shims/extern_static.rs
+++ b/src/tools/miri/src/shims/extern_static.rs
@@ -4,13 +4,13 @@ use crate::*;
 
 impl<'tcx> MiriMachine<'tcx> {
     fn alloc_extern_static(
-        this: &mut MiriInterpCx<'tcx>,
+        ecx: &mut MiriInterpCx<'tcx>,
         name: &str,
         val: ImmTy<'tcx>,
     ) -> InterpResult<'tcx> {
-        let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
-        this.write_immediate(*val, &place)?;
-        Self::add_extern_static(this, name, place.ptr());
+        let place = ecx.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
+        ecx.write_immediate(*val, &place)?;
+        Self::add_extern_static(ecx, name, place.ptr());
         interp_ok(())
     }
 
@@ -18,72 +18,69 @@ impl<'tcx> MiriMachine<'tcx> {
     /// Most of them are for weak symbols, which we all set to null (indicating that the
     /// symbol is not supported, and triggering fallback code which ends up calling
     /// some other shim that we do support).
-    fn null_ptr_extern_statics(
-        this: &mut MiriInterpCx<'tcx>,
-        names: &[&str],
-    ) -> InterpResult<'tcx> {
+    fn null_ptr_extern_statics(ecx: &mut MiriInterpCx<'tcx>, names: &[&str]) -> InterpResult<'tcx> {
         for name in names {
-            let val = ImmTy::from_int(0, this.machine.layouts.usize);
-            Self::alloc_extern_static(this, name, val)?;
+            let val = ImmTy::from_int(0, ecx.machine.layouts.usize);
+            Self::alloc_extern_static(ecx, name, val)?;
         }
         interp_ok(())
     }
 
     /// Extern statics that are initialized with function pointers to the symbols of the same name.
     fn weak_symbol_extern_statics(
-        this: &mut MiriInterpCx<'tcx>,
+        ecx: &mut MiriInterpCx<'tcx>,
         names: &[&str],
     ) -> InterpResult<'tcx> {
         for name in names {
-            assert!(this.is_dyn_sym(name), "{name} is not a dynamic symbol");
-            let layout = this.machine.layouts.const_raw_ptr;
-            let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
-            let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
-            Self::alloc_extern_static(this, name, val)?;
+            assert!(ecx.is_dyn_sym(name), "{name} is not a dynamic symbol");
+            let layout = ecx.machine.layouts.const_raw_ptr;
+            let ptr = ecx.fn_ptr(FnVal::Other(DynSym::from_str(name)));
+            let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, ecx), layout);
+            Self::alloc_extern_static(ecx, name, val)?;
         }
         interp_ok(())
     }
 
     /// Sets up the "extern statics" for this machine.
-    pub fn init_extern_statics(this: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
+    pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
         // "__rust_no_alloc_shim_is_unstable"
-        let val = ImmTy::from_int(0, this.machine.layouts.u8); // always 0, value does not matter
-        Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?;
+        let val = ImmTy::from_int(0, ecx.machine.layouts.u8); // always 0, value does not matter
+        Self::alloc_extern_static(ecx, "__rust_no_alloc_shim_is_unstable", val)?;
 
         // "__rust_alloc_error_handler_should_panic"
-        let val = this.tcx.sess.opts.unstable_opts.oom.should_panic();
-        let val = ImmTy::from_int(val, this.machine.layouts.u8);
-        Self::alloc_extern_static(this, "__rust_alloc_error_handler_should_panic", val)?;
+        let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic();
+        let val = ImmTy::from_int(val, ecx.machine.layouts.u8);
+        Self::alloc_extern_static(ecx, "__rust_alloc_error_handler_should_panic", val)?;
 
-        if this.target_os_is_unix() {
+        if ecx.target_os_is_unix() {
             // "environ" is mandated by POSIX.
-            let environ = this.machine.env_vars.unix().environ();
-            Self::add_extern_static(this, "environ", environ);
+            let environ = ecx.machine.env_vars.unix().environ();
+            Self::add_extern_static(ecx, "environ", environ);
         }
 
-        match this.tcx.sess.target.os.as_ref() {
+        match ecx.tcx.sess.target.os.as_ref() {
             "linux" => {
-                Self::null_ptr_extern_statics(this, &[
+                Self::null_ptr_extern_statics(ecx, &[
                     "__cxa_thread_atexit_impl",
                     "__clock_gettime64",
                 ])?;
-                Self::weak_symbol_extern_statics(this, &["getrandom", "statx"])?;
+                Self::weak_symbol_extern_statics(ecx, &["getrandom", "statx"])?;
             }
             "freebsd" => {
-                Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?;
+                Self::null_ptr_extern_statics(ecx, &["__cxa_thread_atexit_impl"])?;
             }
             "android" => {
-                Self::null_ptr_extern_statics(this, &["bsd_signal"])?;
-                Self::weak_symbol_extern_statics(this, &["signal", "getrandom"])?;
+                Self::null_ptr_extern_statics(ecx, &["bsd_signal"])?;
+                Self::weak_symbol_extern_statics(ecx, &["signal", "getrandom"])?;
             }
             "windows" => {
                 // "_tls_used"
                 // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
-                let val = ImmTy::from_int(0, this.machine.layouts.u8);
-                Self::alloc_extern_static(this, "_tls_used", val)?;
+                let val = ImmTy::from_int(0, ecx.machine.layouts.u8);
+                Self::alloc_extern_static(ecx, "_tls_used", val)?;
             }
             "illumos" | "solaris" => {
-                Self::weak_symbol_extern_statics(this, &["pthread_setname_np"])?;
+                Self::weak_symbol_extern_statics(ecx, &["pthread_setname_np"])?;
             }
             _ => {} // No "extern statics" supported on this target
         }
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index b74491a2f8e..4dc857ef30b 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -496,14 +496,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Rust allocation
             "__rust_alloc" | "miri_alloc" => {
-                let default = |this: &mut MiriInterpCx<'tcx>| {
+                let default = |ecx: &mut MiriInterpCx<'tcx>| {
                     // Only call `check_shim` when `#[global_allocator]` isn't used. When that
                     // macro is used, we act like no shim exists, so that the exported function can run.
-                    let [size, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
-                    let size = this.read_target_usize(size)?;
-                    let align = this.read_target_usize(align)?;
+                    let [size, align] = ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
+                    let size = ecx.read_target_usize(size)?;
+                    let align = ecx.read_target_usize(align)?;
 
-                    this.check_rustc_alloc_request(size, align)?;
+                    ecx.check_rustc_alloc_request(size, align)?;
 
                     let memory_kind = match link_name.as_str() {
                         "__rust_alloc" => MiriMemoryKind::Rust,
@@ -511,13 +511,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         _ => unreachable!(),
                     };
 
-                    let ptr = this.allocate_ptr(
+                    let ptr = ecx.allocate_ptr(
                         Size::from_bytes(size),
                         Align::from_bytes(align).unwrap(),
                         memory_kind.into(),
                     )?;
 
-                    this.write_pointer(ptr, dest)
+                    ecx.write_pointer(ptr, dest)
                 };
 
                 match link_name.as_str() {
@@ -555,14 +555,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 });
             }
             "__rust_dealloc" | "miri_dealloc" => {
-                let default = |this: &mut MiriInterpCx<'tcx>| {
+                let default = |ecx: &mut MiriInterpCx<'tcx>| {
                     // See the comment for `__rust_alloc` why `check_shim` is only called in the
                     // default case.
                     let [ptr, old_size, align] =
-                        this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
-                    let ptr = this.read_pointer(ptr)?;
-                    let old_size = this.read_target_usize(old_size)?;
-                    let align = this.read_target_usize(align)?;
+                        ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
+                    let ptr = ecx.read_pointer(ptr)?;
+                    let old_size = ecx.read_target_usize(old_size)?;
+                    let align = ecx.read_target_usize(align)?;
 
                     let memory_kind = match link_name.as_str() {
                         "__rust_dealloc" => MiriMemoryKind::Rust,
@@ -571,7 +571,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     };
 
                     // No need to check old_size/align; we anyway check that they match the allocation.
-                    this.deallocate_ptr(
+                    ecx.deallocate_ptr(
                         ptr,
                         Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
                         memory_kind.into(),
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
index 093b7405ccd..f8a0b3a85a2 100644
--- a/src/tools/miri/src/shims/unix/android/thread.rs
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -8,7 +8,7 @@ use crate::*;
 const TASK_COMM_LEN: usize = 16;
 
 pub fn prctl<'tcx>(
-    this: &mut MiriInterpCx<'tcx>,
+    ecx: &mut MiriInterpCx<'tcx>,
     link_name: Symbol,
     abi: ExternAbi,
     args: &[OpTy<'tcx>],
@@ -16,41 +16,41 @@ pub fn prctl<'tcx>(
 ) -> InterpResult<'tcx> {
     // We do not use `check_shim` here because `prctl` is variadic. The argument
     // count is checked bellow.
-    this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
+    ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
 
     // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
     let pr_set_name = 15;
     let pr_get_name = 16;
 
     let [op] = check_min_arg_count("prctl", args)?;
-    let res = match this.read_scalar(op)?.to_i32()? {
+    let res = match ecx.read_scalar(op)?.to_i32()? {
         op if op == pr_set_name => {
             let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?;
-            let name = this.read_scalar(name)?;
-            let thread = this.pthread_self()?;
+            let name = ecx.read_scalar(name)?;
+            let thread = ecx.pthread_self()?;
             // The Linux kernel silently truncates long names.
             // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html
             let res =
-                this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
+                ecx.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
             assert_eq!(res, ThreadNameResult::Ok);
             Scalar::from_u32(0)
         }
         op if op == pr_get_name => {
             let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?;
-            let name = this.read_scalar(name)?;
-            let thread = this.pthread_self()?;
-            let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this);
-            this.check_ptr_access(
-                name.to_pointer(this)?,
+            let name = ecx.read_scalar(name)?;
+            let thread = ecx.pthread_self()?;
+            let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx);
+            ecx.check_ptr_access(
+                name.to_pointer(ecx)?,
                 Size::from_bytes(TASK_COMM_LEN),
                 CheckInAllocMsg::MemoryAccessTest,
             )?;
-            let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
+            let res = ecx.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
             assert_eq!(res, ThreadNameResult::Ok);
             Scalar::from_u32(0)
         }
         op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op),
     };
-    this.write_scalar(res, dest)?;
+    ecx.write_scalar(res, dest)?;
     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 35bc933885c..63b7d37b13e 100644
--- a/src/tools/miri/src/shims/unix/linux/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs
@@ -4,7 +4,7 @@ use std::io;
 use std::io::ErrorKind;
 
 use crate::concurrency::VClock;
-use crate::shims::unix::fd::FileDescriptionRef;
+use crate::shims::unix::fd::{FileDescriptionRef, WeakFileDescriptionRef};
 use crate::shims::unix::linux::epoll::{EpollReadyEvents, EvalContextExt as _};
 use crate::shims::unix::*;
 use crate::*;
@@ -26,6 +26,10 @@ struct Event {
     counter: Cell<u64>,
     is_nonblock: bool,
     clock: RefCell<VClock>,
+    /// A list of thread ids blocked on eventfd::read.
+    blocked_read_tid: RefCell<Vec<ThreadId>>,
+    /// A list of thread ids blocked on eventfd::write.
+    blocked_write_tid: RefCell<Vec<ThreadId>>,
 }
 
 impl FileDescription for Event {
@@ -72,31 +76,8 @@ impl FileDescription for Event {
         // eventfd read at the size of u64.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
 
-        // Block when counter == 0.
-        let counter = self.counter.get();
-        if counter == 0 {
-            if self.is_nonblock {
-                return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
-            }
-
-            throw_unsup_format!("eventfd: blocking is unsupported");
-        } else {
-            // Synchronize with all prior `write` calls to this FD.
-            ecx.acquire_clock(&self.clock.borrow());
-
-            // Give old counter value to userspace, and set counter value to 0.
-            ecx.write_int(counter, &buf_place)?;
-            self.counter.set(0);
-
-            // When any of the event happened, we check and update the status of all supported event
-            // types for current file description.
-            ecx.check_and_update_readiness(self_ref)?;
-
-            // Tell userspace how many bytes we wrote.
-            ecx.write_int(buf_place.layout.size.bytes(), dest)?;
-        }
-
-        interp_ok(())
+        let weak_eventfd = self_ref.downgrade();
+        eventfd_read(buf_place, dest, weak_eventfd, ecx)
     }
 
     /// A write call adds the 8-byte integer value supplied in
@@ -127,7 +108,7 @@ impl FileDescription for Event {
             return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
 
-        // Read the user supplied value from the pointer.
+        // Read the user-supplied value from the pointer.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
         let num = ecx.read_scalar(&buf_place)?.to_u64()?;
 
@@ -137,27 +118,8 @@ impl FileDescription for Event {
         }
         // If the addition does not let the counter to exceed the maximum value, update the counter.
         // Else, block.
-        match self.counter.get().checked_add(num) {
-            Some(new_count @ 0..=MAX_COUNTER) => {
-                // Future `read` calls will synchronize with this write, so update the FD clock.
-                ecx.release_clock(|clock| {
-                    self.clock.borrow_mut().join(clock);
-                });
-                self.counter.set(new_count);
-            }
-            None | Some(u64::MAX) =>
-                if self.is_nonblock {
-                    return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
-                } else {
-                    throw_unsup_format!("eventfd: blocking is unsupported");
-                },
-        };
-        // When any of the event happened, we check and update the status of all supported event
-        // types for current file description.
-        ecx.check_and_update_readiness(self_ref)?;
-
-        // Return how many bytes we read.
-        ecx.write_int(buf_place.layout.size.bytes(), dest)
+        let weak_eventfd = self_ref.downgrade();
+        eventfd_write(num, buf_place, dest, weak_eventfd, ecx)
     }
 }
 
@@ -217,8 +179,151 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             counter: Cell::new(val.into()),
             is_nonblock,
             clock: RefCell::new(VClock::default()),
+            blocked_read_tid: RefCell::new(Vec::new()),
+            blocked_write_tid: RefCell::new(Vec::new()),
         });
 
         interp_ok(Scalar::from_i32(fd_value))
     }
 }
+
+/// Block thread if the value addition will exceed u64::MAX -1,
+/// else just add the user-supplied value to current counter.
+fn eventfd_write<'tcx>(
+    num: u64,
+    buf_place: MPlaceTy<'tcx>,
+    dest: &MPlaceTy<'tcx>,
+    weak_eventfd: WeakFileDescriptionRef,
+    ecx: &mut MiriInterpCx<'tcx>,
+) -> InterpResult<'tcx> {
+    let Some(eventfd_ref) = weak_eventfd.upgrade() else {
+        throw_unsup_format!("eventfd FD got closed while blocking.")
+    };
+
+    // Since we pass the weak file description ref, it is guaranteed to be
+    // an eventfd file description.
+    let eventfd = eventfd_ref.downcast::<Event>().unwrap();
+
+    match eventfd.counter.get().checked_add(num) {
+        Some(new_count @ 0..=MAX_COUNTER) => {
+            // Future `read` calls will synchronize with this write, so update the FD clock.
+            ecx.release_clock(|clock| {
+                eventfd.clock.borrow_mut().join(clock);
+            });
+
+            // When this function is called, the addition is guaranteed to not exceed u64::MAX - 1.
+            eventfd.counter.set(new_count);
+
+            // When any of the event happened, we check and update the status of all supported event
+            // types for current file description.
+            ecx.check_and_update_readiness(&eventfd_ref)?;
+
+            // Unblock *all* threads previously blocked on `read`.
+            // We need to take out the blocked thread ids and unblock them together,
+            // because `unblock_threads` may block them again and end up re-adding the
+            // thread to the blocked list.
+            let waiting_threads = std::mem::take(&mut *eventfd.blocked_read_tid.borrow_mut());
+            // FIXME: We can randomize the order of unblocking.
+            for thread_id in waiting_threads {
+                ecx.unblock_thread(thread_id, BlockReason::Eventfd)?;
+            }
+
+            // Return how many bytes we wrote.
+            return ecx.write_int(buf_place.layout.size.bytes(), dest);
+        }
+        None | Some(u64::MAX) => {
+            if eventfd.is_nonblock {
+                return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+            }
+
+            let dest = dest.clone();
+
+            eventfd.blocked_write_tid.borrow_mut().push(ecx.active_thread());
+
+            ecx.block_thread(
+                BlockReason::Eventfd,
+                None,
+                callback!(
+                    @capture<'tcx> {
+                        num: u64,
+                        buf_place: MPlaceTy<'tcx>,
+                        dest: MPlaceTy<'tcx>,
+                        weak_eventfd: WeakFileDescriptionRef,
+                    }
+                    @unblock = |this| {
+                        eventfd_write(num, buf_place, &dest, weak_eventfd, this)
+                    }
+                ),
+            );
+        }
+    };
+    interp_ok(())
+}
+
+/// Block thread if the current counter is 0,
+/// else just return the current counter value to the caller and set the counter to 0.
+fn eventfd_read<'tcx>(
+    buf_place: MPlaceTy<'tcx>,
+    dest: &MPlaceTy<'tcx>,
+    weak_eventfd: WeakFileDescriptionRef,
+    ecx: &mut MiriInterpCx<'tcx>,
+) -> InterpResult<'tcx> {
+    let Some(eventfd_ref) = weak_eventfd.upgrade() else {
+        throw_unsup_format!("eventfd FD got closed while blocking.")
+    };
+
+    // Since we pass the weak file description ref to the callback function, it is guaranteed to be
+    // an eventfd file description.
+    let eventfd = eventfd_ref.downcast::<Event>().unwrap();
+
+    // Block when counter == 0.
+    let counter = eventfd.counter.replace(0);
+
+    if counter == 0 {
+        if eventfd.is_nonblock {
+            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+        }
+        let dest = dest.clone();
+
+        eventfd.blocked_read_tid.borrow_mut().push(ecx.active_thread());
+
+        ecx.block_thread(
+            BlockReason::Eventfd,
+            None,
+            callback!(
+                @capture<'tcx> {
+                    buf_place: MPlaceTy<'tcx>,
+                    dest: MPlaceTy<'tcx>,
+                    weak_eventfd: WeakFileDescriptionRef,
+                }
+                @unblock = |this| {
+                    eventfd_read(buf_place, &dest, weak_eventfd, this)
+                }
+            ),
+        );
+    } else {
+        // Synchronize with all prior `write` calls to this FD.
+        ecx.acquire_clock(&eventfd.clock.borrow());
+
+        // Give old counter value to userspace, and set counter value to 0.
+        ecx.write_int(counter, &buf_place)?;
+
+        // When any of the events happened, we check and update the status of all supported event
+        // types for current file description.
+        ecx.check_and_update_readiness(&eventfd_ref)?;
+
+        // Unblock *all* threads previously blocked on `write`.
+        // We need to take out the blocked thread ids and unblock them together,
+        // because `unblock_threads` may block them again and end up re-adding the
+        // thread to the blocked list.
+        let waiting_threads = std::mem::take(&mut *eventfd.blocked_write_tid.borrow_mut());
+        // FIXME: We can randomize the order of unblocking.
+        for thread_id in waiting_threads {
+            ecx.unblock_thread(thread_id, BlockReason::Eventfd)?;
+        }
+
+        // Tell userspace how many bytes we read.
+        return ecx.write_int(buf_place.layout.size.bytes(), dest);
+    }
+    interp_ok(())
+}
diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs
index 01b011d3504..51124fb2a00 100644
--- a/src/tools/miri/src/shims/unix/linux/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux/sync.rs
@@ -9,7 +9,7 @@ struct LinuxFutex {
 /// Implementation of the SYS_futex syscall.
 /// `args` is the arguments *including* the syscall number.
 pub fn futex<'tcx>(
-    this: &mut MiriInterpCx<'tcx>,
+    ecx: &mut MiriInterpCx<'tcx>,
     args: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
@@ -26,19 +26,19 @@ pub fn futex<'tcx>(
     // 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(addr)?;
-    let op = this.read_scalar(op)?.to_i32()?;
-    let val = this.read_scalar(val)?.to_i32()?;
+    let addr = ecx.read_pointer(addr)?;
+    let op = ecx.read_scalar(op)?.to_i32()?;
+    let val = ecx.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);
+    let addr = ecx.ptr_to_mplace(addr, ecx.machine.layouts.i32);
 
-    let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG");
-    let futex_wait = this.eval_libc_i32("FUTEX_WAIT");
-    let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET");
-    let futex_wake = this.eval_libc_i32("FUTEX_WAKE");
-    let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET");
-    let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME");
+    let futex_private = ecx.eval_libc_i32("FUTEX_PRIVATE_FLAG");
+    let futex_wait = ecx.eval_libc_i32("FUTEX_WAIT");
+    let futex_wait_bitset = ecx.eval_libc_i32("FUTEX_WAIT_BITSET");
+    let futex_wake = ecx.eval_libc_i32("FUTEX_WAKE");
+    let futex_wake_bitset = ecx.eval_libc_i32("FUTEX_WAKE_BITSET");
+    let futex_realtime = ecx.eval_libc_i32("FUTEX_CLOCK_REALTIME");
 
     // FUTEX_PRIVATE enables an optimization that stops it from working across processes.
     // Miri doesn't support that anyway, so we ignore that flag.
@@ -57,9 +57,9 @@ pub fn futex<'tcx>(
             let (timeout, bitset) = if wait_bitset {
                 let [_, _, _, _, timeout, uaddr2, bitset] =
                     check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`", args)?;
-                let _timeout = this.read_pointer(timeout)?;
-                let _uaddr2 = this.read_pointer(uaddr2)?;
-                (timeout, this.read_scalar(bitset)?.to_u32()?)
+                let _timeout = ecx.read_pointer(timeout)?;
+                let _uaddr2 = ecx.read_pointer(uaddr2)?;
+                (timeout, ecx.read_scalar(bitset)?.to_u32()?)
             } else {
                 let [_, _, _, _, timeout] =
                     check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", args)?;
@@ -67,21 +67,21 @@ pub fn futex<'tcx>(
             };
 
             if bitset == 0 {
-                return this.set_last_error_and_return(LibcError("EINVAL"), dest);
+                return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
             }
 
-            let timeout = this.deref_pointer_as(timeout, this.libc_ty_layout("timespec"))?;
-            let timeout = if this.ptr_is_null(timeout.ptr())? {
+            let timeout = ecx.deref_pointer_as(timeout, ecx.libc_ty_layout("timespec"))?;
+            let timeout = if ecx.ptr_is_null(timeout.ptr())? {
                 None
             } else {
-                let duration = match this.read_timespec(&timeout)? {
+                let duration = match ecx.read_timespec(&timeout)? {
                     Some(duration) => duration,
                     None => {
-                        return this.set_last_error_and_return(LibcError("EINVAL"), dest);
+                        return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
                     }
                 };
                 let timeout_clock = if op & futex_realtime == futex_realtime {
-                    this.check_no_isolation(
+                    ecx.check_no_isolation(
                         "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`",
                     )?;
                     TimeoutClock::RealTime
@@ -139,36 +139,36 @@ pub fn futex<'tcx>(
             //
             // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to
             // do anything special to guarantee fence-load-comparison atomicity.
-            this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+            ecx.atomic_fence(AtomicFenceOrd::SeqCst)?;
             // Read an `i32` through the pointer, regardless of any wrapper types.
             // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
             // We do an acquire read -- it only seems reasonable that if we observe a value here, we
             // actually establish an ordering with that value.
-            let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
+            let futex_val = ecx.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
             if val == futex_val {
                 // The value still matches, so we block the thread and make it wait for FUTEX_WAKE.
 
                 // This cannot fail since we already did an atomic acquire read on that pointer.
                 // Acquire reads are only allowed on mutable memory.
-                let futex_ref = this
+                let futex_ref = ecx
                     .get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
                     .unwrap()
                     .futex
                     .clone();
 
-                this.futex_wait(
+                ecx.futex_wait(
                     futex_ref,
                     bitset,
                     timeout,
-                    Scalar::from_target_isize(0, this), // retval_succ
-                    Scalar::from_target_isize(-1, this), // retval_timeout
+                    Scalar::from_target_isize(0, ecx), // retval_succ
+                    Scalar::from_target_isize(-1, ecx), // retval_timeout
                     dest.clone(),
                     LibcError("ETIMEDOUT"), // errno_timeout
                 );
             } else {
                 // The futex value doesn't match the expected value, so we return failure
                 // right away without sleeping: -1 and errno set to EAGAIN.
-                return this.set_last_error_and_return(LibcError("EAGAIN"), dest);
+                return ecx.set_last_error_and_return(LibcError("EAGAIN"), dest);
             }
         }
         // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
@@ -179,42 +179,42 @@ 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 Some(futex_ref) =
-                this.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
+                ecx.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
             else {
                 // No AllocId, or no live allocation at that AllocId.
                 // Return an error code. (That seems nicer than silently doing something non-intuitive.)
                 // This means that if an address gets reused by a new allocation,
                 // we'll use an independent futex queue for this... that seems acceptable.
-                return this.set_last_error_and_return(LibcError("EFAULT"), dest);
+                return ecx.set_last_error_and_return(LibcError("EFAULT"), dest);
             };
             let futex_ref = futex_ref.futex.clone();
 
             let bitset = if op == futex_wake_bitset {
                 let [_, _, _, _, timeout, uaddr2, bitset] =
                     check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?;
-                let _timeout = this.read_pointer(timeout)?;
-                let _uaddr2 = this.read_pointer(uaddr2)?;
-                this.read_scalar(bitset)?.to_u32()?
+                let _timeout = ecx.read_pointer(timeout)?;
+                let _uaddr2 = ecx.read_pointer(uaddr2)?;
+                ecx.read_scalar(bitset)?.to_u32()?
             } else {
                 u32::MAX
             };
             if bitset == 0 {
-                return this.set_last_error_and_return(LibcError("EINVAL"), dest);
+                return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
             }
             // 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
             // before doing the syscall.
-            this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+            ecx.atomic_fence(AtomicFenceOrd::SeqCst)?;
             let mut n = 0;
             #[expect(clippy::arithmetic_side_effects)]
             for _ in 0..val {
-                if this.futex_wake(&futex_ref, bitset)? {
+                if ecx.futex_wake(&futex_ref, bitset)? {
                     n += 1;
                 } else {
                     break;
                 }
             }
-            this.write_scalar(Scalar::from_target_isize(n, this), dest)?;
+            ecx.write_scalar(Scalar::from_target_isize(n, ecx), dest)?;
         }
         op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
     }
diff --git a/src/tools/miri/src/shims/unix/linux/syscall.rs b/src/tools/miri/src/shims/unix/linux/syscall.rs
index 0d7032adab4..9f6935f096b 100644
--- a/src/tools/miri/src/shims/unix/linux/syscall.rs
+++ b/src/tools/miri/src/shims/unix/linux/syscall.rs
@@ -7,7 +7,7 @@ use crate::shims::unix::linux::sync::futex;
 use crate::*;
 
 pub fn syscall<'tcx>(
-    this: &mut MiriInterpCx<'tcx>,
+    ecx: &mut MiriInterpCx<'tcx>,
     link_name: Symbol,
     abi: ExternAbi,
     args: &[OpTy<'tcx>],
@@ -15,18 +15,18 @@ pub fn syscall<'tcx>(
 ) -> InterpResult<'tcx> {
     // We do not use `check_shim` here because `syscall` is variadic. The argument
     // count is checked bellow.
-    this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
+    ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
     // The syscall variadic function is legal to call with more arguments than needed,
     // extra arguments are simply ignored. The important check is that when we use an
     // argument, we have to also check all arguments *before* it to ensure that they
     // have the right type.
 
-    let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?;
-    let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?;
-    let sys_eventfd2 = this.eval_libc("SYS_eventfd2").to_target_usize(this)?;
+    let sys_getrandom = ecx.eval_libc("SYS_getrandom").to_target_usize(ecx)?;
+    let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?;
+    let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?;
 
     let [op] = check_min_arg_count("syscall", args)?;
-    match this.read_target_usize(op)? {
+    match ecx.read_target_usize(op)? {
         // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
         // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
         num if num == sys_getrandom => {
@@ -34,25 +34,25 @@ pub fn syscall<'tcx>(
             // The first argument is the syscall id, so skip over it.
             let [_, ptr, len, flags] = check_min_arg_count("syscall(SYS_getrandom, ...)", args)?;
 
-            let ptr = this.read_pointer(ptr)?;
-            let len = this.read_target_usize(len)?;
+            let ptr = ecx.read_pointer(ptr)?;
+            let len = ecx.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(flags)?.to_i32()?;
+            let _flags = ecx.read_scalar(flags)?.to_i32()?;
 
-            this.gen_random(ptr, len)?;
-            this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
+            ecx.gen_random(ptr, len)?;
+            ecx.write_scalar(Scalar::from_target_usize(len, ecx), dest)?;
         }
         // `futex` is used by some synchronization primitives.
         num if num == sys_futex => {
-            futex(this, args, dest)?;
+            futex(ecx, args, dest)?;
         }
         num if num == sys_eventfd2 => {
             let [_, initval, flags] = check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?;
 
-            let result = this.eventfd(initval, flags)?;
-            this.write_int(result.to_i32()?, dest)?;
+            let result = ecx.eventfd(initval, flags)?;
+            ecx.write_int(result.to_i32()?, dest)?;
         }
         num => {
             throw_unsup_format!("syscall: unsupported syscall number {num}");
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
index ffc8c222738..f66a57ae706 100644
--- a/src/tools/miri/src/shims/unix/macos/sync.rs
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -14,18 +14,21 @@ use rustc_abi::Size;
 
 use crate::*;
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 enum MacOsUnfairLock {
     Poisoned,
-    Active { id: MutexId },
+    Active { mutex_ref: MutexRef },
 }
 
 impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
 trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
-    fn os_unfair_lock_get_data(
-        &mut self,
+    fn os_unfair_lock_get_data<'a>(
+        &'a mut self,
         lock_ptr: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, MacOsUnfairLock> {
+    ) -> InterpResult<'tcx, &'a MacOsUnfairLock>
+    where
+        'tcx: 'a,
+    {
         let this = self.eval_context_mut();
         let lock = this.deref_pointer(lock_ptr)?;
         this.lazy_sync_get_data(
@@ -42,8 +45,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 interp_ok(MacOsUnfairLock::Poisoned)
             },
             |ecx| {
-                let id = ecx.machine.sync.mutex_create();
-                interp_ok(MacOsUnfairLock::Active { id })
+                let mutex_ref = ecx.machine.sync.mutex_create();
+                interp_ok(MacOsUnfairLock::Active { mutex_ref })
             },
         )
     }
@@ -54,7 +57,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // Trying to get a poisoned lock. Just block forever...
             this.block_thread(
                 BlockReason::Sleep,
@@ -68,18 +71,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             );
             return interp_ok(());
         };
+        let mutex_ref = mutex_ref.clone();
 
-        if this.mutex_is_locked(id) {
-            if this.mutex_get_owner(id) == this.active_thread() {
+        if this.mutex_is_locked(&mutex_ref) {
+            if this.mutex_get_owner(&mutex_ref) == this.active_thread() {
                 // Matching the current macOS implementation: abort on reentrant locking.
                 throw_machine_stop!(TerminationInfo::Abort(
                     "attempted to lock an os_unfair_lock that is already locked by the current thread".to_owned()
                 ));
             }
 
-            this.mutex_enqueue_and_block(id, None);
+            this.mutex_enqueue_and_block(&mutex_ref, None);
         } else {
-            this.mutex_lock(id);
+            this.mutex_lock(&mutex_ref);
         }
 
         interp_ok(())
@@ -92,18 +96,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // Trying to get a poisoned lock. That never works.
             this.write_scalar(Scalar::from_bool(false), dest)?;
             return interp_ok(());
         };
+        let mutex_ref = mutex_ref.clone();
 
-        if this.mutex_is_locked(id) {
+        if this.mutex_is_locked(&mutex_ref) {
             // Contrary to the blocking lock function, this does not check for
             // reentrancy.
             this.write_scalar(Scalar::from_bool(false), dest)?;
         } else {
-            this.mutex_lock(id);
+            this.mutex_lock(&mutex_ref);
             this.write_scalar(Scalar::from_bool(true), dest)?;
         }
 
@@ -113,15 +118,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // The lock is poisoned, who knows who owns it... we'll pretend: someone else.
             throw_machine_stop!(TerminationInfo::Abort(
                 "attempted to unlock an os_unfair_lock not owned by the current thread".to_owned()
             ));
         };
+        let mutex_ref = mutex_ref.clone();
 
         // Now, unlock.
-        if this.mutex_unlock(id)?.is_none() {
+        if this.mutex_unlock(&mutex_ref)?.is_none() {
             // Matching the current macOS implementation: abort.
             throw_machine_stop!(TerminationInfo::Abort(
                 "attempted to unlock an os_unfair_lock not owned by the current thread".to_owned()
@@ -130,7 +136,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // If the lock is not locked by anyone now, it went quer.
         // Reset to zero so that it can be moved and initialized again for the next phase.
-        if !this.mutex_is_locked(id) {
+        if !this.mutex_is_locked(&mutex_ref) {
             let lock_place = this.deref_pointer_as(lock_op, this.machine.layouts.u32)?;
             this.write_scalar_atomic(Scalar::from_u32(0), &lock_place, AtomicWriteOrd::Relaxed)?;
         }
@@ -141,13 +147,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // The lock is poisoned, who knows who owns it... we'll pretend: someone else.
             throw_machine_stop!(TerminationInfo::Abort(
                 "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned()
             ));
         };
-        if !this.mutex_is_locked(id) || this.mutex_get_owner(id) != this.active_thread() {
+        let mutex_ref = mutex_ref.clone();
+
+        if !this.mutex_is_locked(&mutex_ref)
+            || this.mutex_get_owner(&mutex_ref) != this.active_thread()
+        {
             throw_machine_stop!(TerminationInfo::Abort(
                 "called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned()
             ));
@@ -161,11 +171,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let MacOsUnfairLock::Active { id } = this.os_unfair_lock_get_data(lock_op)? else {
+        let MacOsUnfairLock::Active { mutex_ref } = this.os_unfair_lock_get_data(lock_op)? else {
             // The lock is poisoned, who knows who owns it... we'll pretend: someone else.
             return interp_ok(());
         };
-        if this.mutex_is_locked(id) && this.mutex_get_owner(id) == this.active_thread() {
+        let mutex_ref = mutex_ref.clone();
+
+        if this.mutex_is_locked(&mutex_ref)
+            && this.mutex_get_owner(&mutex_ref) == this.active_thread()
+        {
             throw_machine_stop!(TerminationInfo::Abort(
                 "called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread".to_owned()
             ));
@@ -173,7 +187,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // If the lock is not locked by anyone now, it went quer.
         // Reset to zero so that it can be moved and initialized again for the next phase.
-        if !this.mutex_is_locked(id) {
+        if !this.mutex_is_locked(&mutex_ref) {
             let lock_place = this.deref_pointer_as(lock_op, this.machine.layouts.u32)?;
             this.write_scalar_atomic(Scalar::from_u32(0), &lock_place, AtomicWriteOrd::Relaxed)?;
         }
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index 850626d89ac..416cf020dcc 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -116,9 +116,9 @@ enum MutexKind {
     ErrorCheck,
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
 struct PthreadMutex {
-    id: MutexId,
+    mutex_ref: MutexRef,
     kind: MutexKind,
 }
 
@@ -175,19 +175,20 @@ fn mutex_create<'tcx>(
 ) -> InterpResult<'tcx, PthreadMutex> {
     let mutex = ecx.deref_pointer(mutex_ptr)?;
     let id = ecx.machine.sync.mutex_create();
-    let data = PthreadMutex { id, kind };
-    ecx.lazy_sync_init(&mutex, mutex_init_offset(ecx)?, data)?;
+    let data = PthreadMutex { mutex_ref: id, kind };
+    ecx.lazy_sync_init(&mutex, mutex_init_offset(ecx)?, data.clone())?;
     interp_ok(data)
 }
 
-/// Returns the `MutexId` of the mutex stored at `mutex_op`.
-///
-/// `mutex_get_id` will also check if the mutex has been moved since its first use and
-/// return an error if it has.
+/// Returns the mutex data stored at the address that `mutex_ptr` points to.
+/// Will raise an error if the mutex has been moved since its first use.
 fn mutex_get_data<'tcx, 'a>(
     ecx: &'a mut MiriInterpCx<'tcx>,
     mutex_ptr: &OpTy<'tcx>,
-) -> InterpResult<'tcx, PthreadMutex> {
+) -> InterpResult<'tcx, &'a PthreadMutex>
+where
+    'tcx: 'a,
+{
     let mutex = ecx.deref_pointer(mutex_ptr)?;
     ecx.lazy_sync_get_data(
         &mutex,
@@ -196,7 +197,7 @@ fn mutex_get_data<'tcx, 'a>(
         |ecx| {
             let kind = mutex_kind_from_static_initializer(ecx, &mutex)?;
             let id = ecx.machine.sync.mutex_create();
-            interp_ok(PthreadMutex { id, kind })
+            interp_ok(PthreadMutex { mutex_ref: id, kind })
         },
     )
 }
@@ -261,10 +262,13 @@ fn rwlock_init_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, Size
     interp_ok(offset)
 }
 
-fn rwlock_get_data<'tcx>(
-    ecx: &mut MiriInterpCx<'tcx>,
+fn rwlock_get_data<'tcx, 'a>(
+    ecx: &'a mut MiriInterpCx<'tcx>,
     rwlock_ptr: &OpTy<'tcx>,
-) -> InterpResult<'tcx, PthreadRwLock> {
+) -> InterpResult<'tcx, &'a PthreadRwLock>
+where
+    'tcx: 'a,
+{
     let rwlock = ecx.deref_pointer(rwlock_ptr)?;
     ecx.lazy_sync_get_data(
         &rwlock,
@@ -391,10 +395,13 @@ fn cond_create<'tcx>(
     interp_ok(data)
 }
 
-fn cond_get_data<'tcx>(
-    ecx: &mut MiriInterpCx<'tcx>,
+fn cond_get_data<'tcx, 'a>(
+    ecx: &'a mut MiriInterpCx<'tcx>,
     cond_ptr: &OpTy<'tcx>,
-) -> InterpResult<'tcx, PthreadCondvar> {
+) -> InterpResult<'tcx, &'a PthreadCondvar>
+where
+    'tcx: 'a,
+{
     let cond = ecx.deref_pointer(cond_ptr)?;
     ecx.lazy_sync_get_data(
         &cond,
@@ -500,12 +507,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let mutex = mutex_get_data(this, mutex_op)?;
+        let mutex = mutex_get_data(this, mutex_op)?.clone();
 
-        let ret = if this.mutex_is_locked(mutex.id) {
-            let owner_thread = this.mutex_get_owner(mutex.id);
+        let ret = if this.mutex_is_locked(&mutex.mutex_ref) {
+            let owner_thread = this.mutex_get_owner(&mutex.mutex_ref);
             if owner_thread != this.active_thread() {
-                this.mutex_enqueue_and_block(mutex.id, Some((Scalar::from_i32(0), dest.clone())));
+                this.mutex_enqueue_and_block(
+                    &mutex.mutex_ref,
+                    Some((Scalar::from_i32(0), dest.clone())),
+                );
                 return interp_ok(());
             } else {
                 // Trying to acquire the same mutex again.
@@ -517,14 +527,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock),
                     MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"),
                     MutexKind::Recursive => {
-                        this.mutex_lock(mutex.id);
+                        this.mutex_lock(&mutex.mutex_ref);
                         0
                     }
                 }
             }
         } else {
             // The mutex is unlocked. Let's lock it.
-            this.mutex_lock(mutex.id);
+            this.mutex_lock(&mutex.mutex_ref);
             0
         };
         this.write_scalar(Scalar::from_i32(ret), dest)?;
@@ -534,10 +544,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let mutex = mutex_get_data(this, mutex_op)?;
+        let mutex = mutex_get_data(this, mutex_op)?.clone();
 
-        interp_ok(Scalar::from_i32(if this.mutex_is_locked(mutex.id) {
-            let owner_thread = this.mutex_get_owner(mutex.id);
+        interp_ok(Scalar::from_i32(if this.mutex_is_locked(&mutex.mutex_ref) {
+            let owner_thread = this.mutex_get_owner(&mutex.mutex_ref);
             if owner_thread != this.active_thread() {
                 this.eval_libc_i32("EBUSY")
             } else {
@@ -545,14 +555,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     MutexKind::Default | MutexKind::Normal | MutexKind::ErrorCheck =>
                         this.eval_libc_i32("EBUSY"),
                     MutexKind::Recursive => {
-                        this.mutex_lock(mutex.id);
+                        this.mutex_lock(&mutex.mutex_ref);
                         0
                     }
                 }
             }
         } else {
             // The mutex is unlocked. Let's lock it.
-            this.mutex_lock(mutex.id);
+            this.mutex_lock(&mutex.mutex_ref);
             0
         }))
     }
@@ -560,9 +570,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
-        let mutex = mutex_get_data(this, mutex_op)?;
+        let mutex = mutex_get_data(this, mutex_op)?.clone();
 
-        if let Some(_old_locked_count) = this.mutex_unlock(mutex.id)? {
+        if let Some(_old_locked_count) = this.mutex_unlock(&mutex.mutex_ref)? {
             // The mutex was locked by the current thread.
             interp_ok(Scalar::from_i32(0))
         } else {
@@ -588,10 +598,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // Reading the field also has the side-effect that we detect double-`destroy`
-        // since we make the field unint below.
-        let mutex = mutex_get_data(this, mutex_op)?;
+        // since we make the field uninit below.
+        let mutex = mutex_get_data(this, mutex_op)?.clone();
 
-        if this.mutex_is_locked(mutex.id) {
+        if this.mutex_is_locked(&mutex.mutex_ref) {
             throw_ub_format!("destroyed a locked mutex");
         }
 
@@ -696,7 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // Reading the field also has the side-effect that we detect double-`destroy`
-        // since we make the field unint below.
+        // since we make the field uninit below.
         let id = rwlock_get_data(this, rwlock_op)?.id;
 
         if this.rwlock_is_locked(id) {
@@ -821,12 +831,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let data = cond_get_data(this, cond_op)?;
-        let mutex_id = mutex_get_data(this, mutex_op)?.id;
+        let data = *cond_get_data(this, cond_op)?;
+        let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref.clone();
 
         this.condvar_wait(
             data.id,
-            mutex_id,
+            mutex_ref,
             None, // no timeout
             Scalar::from_i32(0),
             Scalar::from_i32(0), // retval_timeout -- unused
@@ -845,8 +855,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
-        let data = cond_get_data(this, cond_op)?;
-        let mutex_id = mutex_get_data(this, mutex_op)?.id;
+        let data = *cond_get_data(this, cond_op)?;
+        let mutex_ref = mutex_get_data(this, mutex_op)?.mutex_ref.clone();
 
         // Extract the timeout.
         let duration = match this
@@ -869,7 +879,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         this.condvar_wait(
             data.id,
-            mutex_id,
+            mutex_ref,
             Some((timeout_clock, TimeoutAnchor::Absolute, duration)),
             Scalar::from_i32(0),
             this.eval_libc("ETIMEDOUT"), // retval_timeout
@@ -883,7 +893,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // Reading the field also has the side-effect that we detect double-`destroy`
-        // since we make the field unint below.
+        // since we make the field uninit below.
         let id = cond_get_data(this, cond_op)?.id;
         if this.condvar_is_awaited(id) {
             throw_ub_format!("destroying an awaited conditional variable");
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 504efed3cfd..c145cf3ceb8 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -7,6 +7,7 @@ use rustc_span::Symbol;
 
 use self::shims::windows::handle::{Handle, PseudoHandle};
 use crate::shims::os_str::bytes_to_os_str;
+use crate::shims::windows::handle::HandleError;
 use crate::shims::windows::*;
 use crate::*;
 
@@ -488,7 +489,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let thread_id =
                     this.CreateThread(security, stacksize, start, arg, flags, thread)?;
 
-                this.write_scalar(Handle::Thread(thread_id.to_u32()).to_scalar(this), dest)?;
+                this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
             }
             "WaitForSingleObject" => {
                 let [handle, timeout] =
@@ -513,10 +514,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let handle = this.read_scalar(handle)?;
                 let name = this.read_wide_str(this.read_pointer(name)?)?;
 
-                let thread = match Handle::from_scalar(handle, this)? {
-                    Some(Handle::Thread(thread)) => this.thread_id_try_from(thread),
-                    Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
-                    _ => this.invalid_handle("SetThreadDescription")?,
+                let thread = match Handle::try_from_scalar(handle, this)? {
+                    Ok(Handle::Thread(thread)) => Ok(thread),
+                    Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
+                    Ok(_) | Err(HandleError::InvalidHandle) =>
+                        this.invalid_handle("SetThreadDescription")?,
+                    Err(HandleError::ThreadNotFound(e)) => Err(e),
                 };
                 let res = match thread {
                     Ok(thread) => {
@@ -536,10 +539,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let handle = this.read_scalar(handle)?;
                 let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name
 
-                let thread = match Handle::from_scalar(handle, this)? {
-                    Some(Handle::Thread(thread)) => this.thread_id_try_from(thread),
-                    Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
-                    _ => this.invalid_handle("GetThreadDescription")?,
+                let thread = match Handle::try_from_scalar(handle, this)? {
+                    Ok(Handle::Thread(thread)) => Ok(thread),
+                    Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
+                    Ok(_) | Err(HandleError::InvalidHandle) =>
+                        this.invalid_handle("GetThreadDescription")?,
+                    Err(HandleError::ThreadNotFound(e)) => Err(e),
                 };
                 let (name, res) = match thread {
                     Ok(thread) => {
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index b40c00efedd..3d872b65a63 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -2,6 +2,7 @@ use std::mem::variant_count;
 
 use rustc_abi::HasDataLayout;
 
+use crate::concurrency::thread::ThreadNotFound;
 use crate::*;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -14,7 +15,7 @@ pub enum PseudoHandle {
 pub enum Handle {
     Null,
     Pseudo(PseudoHandle),
-    Thread(u32),
+    Thread(ThreadId),
 }
 
 impl PseudoHandle {
@@ -34,6 +35,14 @@ impl PseudoHandle {
     }
 }
 
+/// Errors that can occur when constructing a [`Handle`] from a Scalar.
+pub enum HandleError {
+    /// There is no thread with the given ID.
+    ThreadNotFound(ThreadNotFound),
+    /// Can't convert scalar to handle because it is structurally invalid.
+    InvalidHandle,
+}
+
 impl Handle {
     const NULL_DISCRIMINANT: u32 = 0;
     const PSEUDO_DISCRIMINANT: u32 = 1;
@@ -51,7 +60,7 @@ impl Handle {
         match self {
             Self::Null => 0,
             Self::Pseudo(pseudo_handle) => pseudo_handle.value(),
-            Self::Thread(thread) => thread,
+            Self::Thread(thread) => thread.to_u32(),
         }
     }
 
@@ -95,7 +104,7 @@ impl Handle {
         match discriminant {
             Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null),
             Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)),
-            Self::THREAD_DISCRIMINANT => Some(Self::Thread(data)),
+            Self::THREAD_DISCRIMINANT => Some(Self::Thread(ThreadId::new_unchecked(data))),
             _ => None,
         }
     }
@@ -126,10 +135,14 @@ impl Handle {
         Scalar::from_target_isize(signed_handle.into(), cx)
     }
 
-    pub fn from_scalar<'tcx>(
+    /// Convert a scalar into a structured `Handle`.
+    /// Structurally invalid handles return [`HandleError::InvalidHandle`].
+    /// If the handle is structurally valid but semantically invalid, e.g. a for non-existent thread
+    /// ID, returns [`HandleError::ThreadNotFound`].
+    pub fn try_from_scalar<'tcx>(
         handle: Scalar,
-        cx: &impl HasDataLayout,
-    ) -> InterpResult<'tcx, Option<Self>> {
+        cx: &MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, Result<Self, HandleError>> {
         let sign_extended_handle = handle.to_target_isize(cx)?;
 
         #[expect(clippy::cast_sign_loss)] // we want to lose the sign
@@ -137,10 +150,20 @@ impl Handle {
             signed_handle as u32
         } else {
             // if a handle doesn't fit in an i32, it isn't valid.
-            return interp_ok(None);
+            return interp_ok(Err(HandleError::InvalidHandle));
         };
 
-        interp_ok(Self::from_packed(handle))
+        match Self::from_packed(handle) {
+            Some(Self::Thread(thread)) => {
+                // validate the thread id
+                match cx.machine.threads.thread_id_try_from(thread.to_u32()) {
+                    Ok(id) => interp_ok(Ok(Self::Thread(id))),
+                    Err(e) => interp_ok(Err(HandleError::ThreadNotFound(e))),
+                }
+            }
+            Some(handle) => interp_ok(Ok(handle)),
+            None => interp_ok(Err(HandleError::InvalidHandle)),
+        }
     }
 }
 
@@ -158,14 +181,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let handle = this.read_scalar(handle_op)?;
-        let ret = match Handle::from_scalar(handle, this)? {
-            Some(Handle::Thread(thread)) => {
-                if let Ok(thread) = this.thread_id_try_from(thread) {
-                    this.detach_thread(thread, /*allow_terminated_joined*/ true)?;
-                    this.eval_windows("c", "TRUE")
-                } else {
-                    this.invalid_handle("CloseHandle")?
-                }
+        let ret = match Handle::try_from_scalar(handle, this)? {
+            Ok(Handle::Thread(thread)) => {
+                this.detach_thread(thread, /*allow_terminated_joined*/ true)?;
+                this.eval_windows("c", "TRUE")
             }
             _ => this.invalid_handle("CloseHandle")?,
         };
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index b03dedea146..a394e0430bc 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -20,10 +20,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     // Windows sync primitives are pointer sized.
     // We only use the first 4 bytes for the id.
 
-    fn init_once_get_data(
-        &mut self,
+    fn init_once_get_data<'a>(
+        &'a mut self,
         init_once_ptr: &OpTy<'tcx>,
-    ) -> InterpResult<'tcx, WindowsInitOnce> {
+    ) -> InterpResult<'tcx, &'a WindowsInitOnce>
+    where
+        'tcx: 'a,
+    {
         let this = self.eval_context_mut();
 
         let init_once = this.deref_pointer(init_once_ptr)?;
diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs
index 7af15fc647c..efc1c2286bc 100644
--- a/src/tools/miri/src/shims/windows/thread.rs
+++ b/src/tools/miri/src/shims/windows/thread.rs
@@ -65,15 +65,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let handle = this.read_scalar(handle_op)?;
         let timeout = this.read_scalar(timeout_op)?.to_u32()?;
 
-        let thread = match Handle::from_scalar(handle, this)? {
-            Some(Handle::Thread(thread)) =>
-                match this.thread_id_try_from(thread) {
-                    Ok(thread) => thread,
-                    Err(_) => this.invalid_handle("WaitForSingleObject")?,
-                },
+        let thread = match Handle::try_from_scalar(handle, this)? {
+            Ok(Handle::Thread(thread)) => thread,
             // Unlike on posix, the outcome of joining the current thread is not documented.
             // On current Windows, it just deadlocks.
-            Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(),
+            Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(),
             _ => this.invalid_handle("WaitForSingleObject")?,
         };
 
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index 33b1f27713c..4c6c1cefeb1 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -132,7 +132,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 // Performs an AES round (given by `f`) on each 128-bit word of
 // `state` with the corresponding 128-bit key of `key`.
 fn aes_round<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     state: &OpTy<'tcx>,
     key: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
@@ -145,21 +145,20 @@ fn aes_round<'tcx>(
     assert_eq!(dest.layout.size.bytes() % 16, 0);
     let len = dest.layout.size.bytes() / 16;
 
-    let u128_array_layout =
-        this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u128, len))?;
+    let u128_array_layout = ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u128, len))?;
 
-    let state = state.transmute(u128_array_layout, this)?;
-    let key = key.transmute(u128_array_layout, this)?;
-    let dest = dest.transmute(u128_array_layout, this)?;
+    let state = state.transmute(u128_array_layout, ecx)?;
+    let key = key.transmute(u128_array_layout, ecx)?;
+    let dest = dest.transmute(u128_array_layout, ecx)?;
 
     for i in 0..len {
-        let state = this.read_scalar(&this.project_index(&state, i)?)?.to_u128()?;
-        let key = this.read_scalar(&this.project_index(&key, i)?)?.to_u128()?;
-        let dest = this.project_index(&dest, i)?;
+        let state = ecx.read_scalar(&ecx.project_index(&state, i)?)?.to_u128()?;
+        let key = ecx.read_scalar(&ecx.project_index(&key, i)?)?.to_u128()?;
+        let dest = ecx.project_index(&dest, i)?;
 
         let res = f(state, key);
 
-        this.write_scalar(Scalar::from_u128(res), &dest)?;
+        ecx.write_scalar(Scalar::from_u128(res), &dest)?;
     }
 
     interp_ok(())
diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs
index 7b92d422cc5..92010345f55 100644
--- a/src/tools/miri/src/shims/x86/gfni.rs
+++ b/src/tools/miri/src/shims/x86/gfni.rs
@@ -75,21 +75,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 /// 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>,
+    ecx: &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)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (right, right_len) = ecx.project_to_simd(right)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, right_len);
     assert_eq!(dest_len, left_len);
 
-    let imm8 = this.read_scalar(imm8)?.to_u8()?;
+    let imm8 = ecx.read_scalar(imm8)?.to_u8()?;
 
     // Each 8x8 bit matrix gets multiplied with eight bit vectors.
     // Therefore, the iteration is done in chunks of eight.
@@ -98,13 +98,13 @@ fn affine_transform<'tcx>(
         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()?;
+                ecx.read_scalar(&ecx.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 = ecx.read_scalar(&ecx.project_index(&left, index)?)?.to_u8()?;
             let left = if inverse { TABLE[usize::from(left)] } else { left };
 
             let mut res = 0;
@@ -124,8 +124,8 @@ fn affine_transform<'tcx>(
             // Perform the addition.
             res ^= imm8;
 
-            let dest = this.project_index(&dest, index)?;
-            this.write_scalar(Scalar::from_u8(res), &dest)?;
+            let dest = ecx.project_index(&dest, index)?;
+            ecx.write_scalar(Scalar::from_u8(res), &dest)?;
         }
     }
 
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 433e9e966f2..3e02a4b3637 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1,4 +1,3 @@
-use rand::Rng as _;
 use rustc_abi::{ExternAbi, Size};
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::Single;
@@ -226,7 +225,7 @@ impl FloatBinOp {
     /// Convert from the `imm` argument used to specify the comparison
     /// operation in intrinsics such as `llvm.x86.sse.cmp.ss`.
     fn cmp_from_imm<'tcx>(
-        this: &crate::MiriInterpCx<'tcx>,
+        ecx: &crate::MiriInterpCx<'tcx>,
         imm: i8,
         intrinsic: Symbol,
     ) -> InterpResult<'tcx, Self> {
@@ -260,7 +259,7 @@ impl FloatBinOp {
         };
         // When bit 3 is 1 (only possible in AVX), unord is toggled.
         if imm & 0b1000 != 0 {
-            this.expect_target_feature_for_intrinsic(intrinsic, "avx")?;
+            ecx.expect_target_feature_for_intrinsic(intrinsic, "avx")?;
             unord = !unord;
         }
         interp_ok(Self::Cmp { gt, lt, eq, unord })
@@ -327,28 +326,28 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
 /// Performs `which` operation on the first component of `left` and `right`
 /// and copies the other components from `left`. The result is stored in `dest`.
 fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     which: FloatBinOp,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> 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)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (right, right_len) = ecx.project_to_simd(right)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, left_len);
     assert_eq!(dest_len, right_len);
 
     let res0 = bin_op_float::<F>(
         which,
-        &this.read_immediate(&this.project_index(&left, 0)?)?,
-        &this.read_immediate(&this.project_index(&right, 0)?)?,
+        &ecx.read_immediate(&ecx.project_index(&left, 0)?)?,
+        &ecx.read_immediate(&ecx.project_index(&right, 0)?)?,
     )?;
-    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+    ecx.write_scalar(res0, &ecx.project_index(&dest, 0)?)?;
 
     for i in 1..dest_len {
-        this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
+        ecx.copy_op(&ecx.project_index(&left, i)?, &ecx.project_index(&dest, i)?)?;
     }
 
     interp_ok(())
@@ -357,26 +356,26 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>(
 /// Performs `which` operation on each component of `left` and
 /// `right`, storing the result is stored in `dest`.
 fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     which: FloatBinOp,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> 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)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (right, right_len) = ecx.project_to_simd(right)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, left_len);
     assert_eq!(dest_len, right_len);
 
     for i in 0..dest_len {
-        let left = this.read_immediate(&this.project_index(&left, i)?)?;
-        let right = this.read_immediate(&this.project_index(&right, i)?)?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.read_immediate(&ecx.project_index(&left, i)?)?;
+        let right = ecx.read_immediate(&ecx.project_index(&right, i)?)?;
+        let dest = ecx.project_index(&dest, i)?;
 
         let res = bin_op_float::<F>(which, &left, &right)?;
-        this.write_scalar(res, &dest)?;
+        ecx.write_scalar(res, &dest)?;
     }
 
     interp_ok(())
@@ -398,7 +397,7 @@ enum FloatUnaryOp {
 
 /// Performs `which` scalar operation on `op` and returns the result.
 fn unary_op_f32<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     which: FloatUnaryOp,
     op: &ImmTy<'tcx>,
 ) -> InterpResult<'tcx, Scalar> {
@@ -408,56 +407,38 @@ fn unary_op_f32<'tcx>(
             let div = (Single::from_u128(1).value / op).value;
             // 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);
+            let res = math::apply_random_float_error(ecx, div, -12);
             interp_ok(Scalar::from_f32(res))
         }
         FloatUnaryOp::Rsqrt => {
-            let op = op.to_scalar().to_u32()?;
-            // FIXME using host floats
-            let sqrt = Single::from_bits(f32::from_bits(op).sqrt().to_bits().into());
-            let rsqrt = (Single::from_u128(1).value / sqrt).value;
+            let op = op.to_scalar().to_f32()?;
+            let rsqrt = (Single::from_u128(1).value / math::sqrt(op)).value;
             // 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);
+            let res = math::apply_random_float_error(ecx, rsqrt, -12);
             interp_ok(Scalar::from_f32(res))
         }
     }
 }
 
-/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale).
-#[expect(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic
-fn apply_random_float_error<F: rustc_apfloat::Float>(
-    this: &mut crate::MiriInterpCx<'_>,
-    val: F,
-    err_scale: i32,
-) -> F {
-    let rng = this.machine.rng.get_mut();
-    // generates rand(0, 2^64) * 2^(scale - 64) = rand(0, 1) * 2^scale
-    let err = F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.strict_sub(64));
-    // give it a random sign
-    let err = if rng.gen::<bool>() { -err } else { err };
-    // multiple the value with (1+err)
-    (val * (F::from_u128(1).value + err).value).value
-}
-
 /// Performs `which` operation on the first component of `op` and copies
 /// the other components. The result is stored in `dest`.
 fn unary_op_ss<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     which: FloatUnaryOp,
     op: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (op, op_len) = this.project_to_simd(op)?;
-    let (dest, dest_len) = this.project_to_simd(dest)?;
+    let (op, op_len) = ecx.project_to_simd(op)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, op_len);
 
-    let res0 = unary_op_f32(this, which, &this.read_immediate(&this.project_index(&op, 0)?)?)?;
-    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+    let res0 = unary_op_f32(ecx, which, &ecx.read_immediate(&ecx.project_index(&op, 0)?)?)?;
+    ecx.write_scalar(res0, &ecx.project_index(&dest, 0)?)?;
 
     for i in 1..dest_len {
-        this.copy_op(&this.project_index(&op, i)?, &this.project_index(&dest, i)?)?;
+        ecx.copy_op(&ecx.project_index(&op, i)?, &ecx.project_index(&dest, i)?)?;
     }
 
     interp_ok(())
@@ -466,22 +447,22 @@ fn unary_op_ss<'tcx>(
 /// Performs `which` operation on each component of `op`, storing the
 /// result is stored in `dest`.
 fn unary_op_ps<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     which: FloatUnaryOp,
     op: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (op, op_len) = this.project_to_simd(op)?;
-    let (dest, dest_len) = this.project_to_simd(dest)?;
+    let (op, op_len) = ecx.project_to_simd(op)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, op_len);
 
     for i in 0..dest_len {
-        let op = this.read_immediate(&this.project_index(&op, i)?)?;
-        let dest = this.project_index(&dest, i)?;
+        let op = ecx.read_immediate(&ecx.project_index(&op, i)?)?;
+        let dest = ecx.project_index(&dest, i)?;
 
-        let res = unary_op_f32(this, which, &op)?;
-        this.write_scalar(res, &dest)?;
+        let res = unary_op_f32(ecx, which, &op)?;
+        ecx.write_scalar(res, &dest)?;
     }
 
     interp_ok(())
@@ -503,14 +484,14 @@ enum ShiftOp {
 /// For arithmetic right-shifts, when right is larger than BITS - 1, the sign
 /// bit is copied to all bits.
 fn shift_simd_by_scalar<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     which: ShiftOp,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (left, left_len) = this.project_to_simd(left)?;
-    let (dest, dest_len) = this.project_to_simd(dest)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, left_len);
     // `right` may have a different length, and we only care about its
@@ -520,11 +501,11 @@ fn shift_simd_by_scalar<'tcx>(
     // by checked_{shl,shr} (u32).
     // It is ok to saturate the value to u32::MAX because any value
     // above BITS - 1 will produce the same result.
-    let shift = u32::try_from(extract_first_u64(this, right)?).unwrap_or(u32::MAX);
+    let shift = u32::try_from(extract_first_u64(ecx, right)?).unwrap_or(u32::MAX);
 
     for i in 0..dest_len {
-        let left = this.read_scalar(&this.project_index(&left, i)?)?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.read_scalar(&ecx.project_index(&left, i)?)?;
+        let dest = ecx.project_index(&dest, i)?;
 
         let res = match which {
             ShiftOp::Left => {
@@ -547,7 +528,7 @@ fn shift_simd_by_scalar<'tcx>(
                 Scalar::from_int(res, dest.layout.size)
             }
         };
-        this.write_scalar(res, &dest)?;
+        ecx.write_scalar(res, &dest)?;
     }
 
     interp_ok(())
@@ -559,23 +540,23 @@ fn shift_simd_by_scalar<'tcx>(
 /// For arithmetic right-shifts, when right is larger than BITS - 1, the sign
 /// bit is copied to all bits.
 fn shift_simd_by_simd<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     which: ShiftOp,
     dest: &MPlaceTy<'tcx>,
 ) -> 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)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (right, right_len) = ecx.project_to_simd(right)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, left_len);
     assert_eq!(dest_len, right_len);
 
     for i in 0..dest_len {
-        let left = this.read_scalar(&this.project_index(&left, i)?)?;
-        let right = this.read_scalar(&this.project_index(&right, i)?)?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.read_scalar(&ecx.project_index(&left, i)?)?;
+        let right = ecx.read_scalar(&ecx.project_index(&right, i)?)?;
+        let dest = ecx.project_index(&dest, i)?;
 
         // It is ok to saturate the value to u32::MAX because any value
         // above BITS - 1 will produce the same result.
@@ -602,7 +583,7 @@ fn shift_simd_by_simd<'tcx>(
                 Scalar::from_int(res, dest.layout.size)
             }
         };
-        this.write_scalar(res, &dest)?;
+        ecx.write_scalar(res, &dest)?;
     }
 
     interp_ok(())
@@ -611,44 +592,44 @@ fn shift_simd_by_simd<'tcx>(
 /// Takes a 128-bit vector, transmutes it to `[u64; 2]` and extracts
 /// the first value.
 fn extract_first_u64<'tcx>(
-    this: &crate::MiriInterpCx<'tcx>,
+    ecx: &crate::MiriInterpCx<'tcx>,
     op: &OpTy<'tcx>,
 ) -> InterpResult<'tcx, u64> {
     // Transmute vector to `[u64; 2]`
-    let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?;
-    let op = op.transmute(array_layout, this)?;
+    let array_layout = ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u64, 2))?;
+    let op = op.transmute(array_layout, ecx)?;
 
     // Get the first u64 from the array
-    this.read_scalar(&this.project_index(&op, 0)?)?.to_u64()
+    ecx.read_scalar(&ecx.project_index(&op, 0)?)?.to_u64()
 }
 
 // Rounds the first element of `right` according to `rounding`
 // and copies the remaining elements from `left`.
 fn round_first<'tcx, F: rustc_apfloat::Float>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     rounding: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> 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)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (right, right_len) = ecx.project_to_simd(right)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, left_len);
     assert_eq!(dest_len, right_len);
 
-    let rounding = rounding_from_imm(this.read_scalar(rounding)?.to_i32()?)?;
+    let rounding = rounding_from_imm(ecx.read_scalar(rounding)?.to_i32()?)?;
 
-    let op0: F = this.read_scalar(&this.project_index(&right, 0)?)?.to_float()?;
+    let op0: F = ecx.read_scalar(&ecx.project_index(&right, 0)?)?.to_float()?;
     let res = op0.round_to_integral(rounding).value;
-    this.write_scalar(
+    ecx.write_scalar(
         Scalar::from_uint(res.to_bits(), Size::from_bits(F::BITS)),
-        &this.project_index(&dest, 0)?,
+        &ecx.project_index(&dest, 0)?,
     )?;
 
     for i in 1..dest_len {
-        this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
+        ecx.copy_op(&ecx.project_index(&left, i)?, &ecx.project_index(&dest, i)?)?;
     }
 
     interp_ok(())
@@ -656,24 +637,24 @@ fn round_first<'tcx, F: rustc_apfloat::Float>(
 
 // Rounds all elements of `op` according to `rounding`.
 fn round_all<'tcx, F: rustc_apfloat::Float>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     op: &OpTy<'tcx>,
     rounding: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (op, op_len) = this.project_to_simd(op)?;
-    let (dest, dest_len) = this.project_to_simd(dest)?;
+    let (op, op_len) = ecx.project_to_simd(op)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, op_len);
 
-    let rounding = rounding_from_imm(this.read_scalar(rounding)?.to_i32()?)?;
+    let rounding = rounding_from_imm(ecx.read_scalar(rounding)?.to_i32()?)?;
 
     for i in 0..dest_len {
-        let op: F = this.read_scalar(&this.project_index(&op, i)?)?.to_float()?;
+        let op: F = ecx.read_scalar(&ecx.project_index(&op, i)?)?.to_float()?;
         let res = op.round_to_integral(rounding).value;
-        this.write_scalar(
+        ecx.write_scalar(
             Scalar::from_uint(res.to_bits(), Size::from_bits(F::BITS)),
-            &this.project_index(&dest, i)?,
+            &ecx.project_index(&dest, i)?,
         )?;
     }
 
@@ -708,31 +689,31 @@ fn rounding_from_imm<'tcx>(rounding: i32) -> InterpResult<'tcx, rustc_apfloat::R
 /// If `op` has more elements than `dest`, extra elements are ignored. If `op`
 /// has less elements than `dest`, the rest is filled with zeros.
 fn convert_float_to_int<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     op: &OpTy<'tcx>,
     rnd: rustc_apfloat::Round,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (op, op_len) = this.project_to_simd(op)?;
-    let (dest, dest_len) = this.project_to_simd(dest)?;
+    let (op, op_len) = ecx.project_to_simd(op)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     // Output must be *signed* integers.
-    assert!(matches!(dest.layout.field(this, 0).ty.kind(), ty::Int(_)));
+    assert!(matches!(dest.layout.field(ecx, 0).ty.kind(), ty::Int(_)));
 
     for i in 0..op_len.min(dest_len) {
-        let op = this.read_immediate(&this.project_index(&op, i)?)?;
-        let dest = this.project_index(&dest, i)?;
+        let op = ecx.read_immediate(&ecx.project_index(&op, i)?)?;
+        let dest = ecx.project_index(&dest, i)?;
 
-        let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
+        let res = ecx.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| {
             // Fallback to minimum according to SSE/AVX semantics.
             ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout)
         });
-        this.write_immediate(*res, &dest)?;
+        ecx.write_immediate(*res, &dest)?;
     }
     // Fill remainder with zeros
     for i in op_len..dest_len {
-        let dest = this.project_index(&dest, i)?;
-        this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
+        let dest = ecx.project_index(&dest, i)?;
+        ecx.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
     }
 
     interp_ok(())
@@ -743,26 +724,26 @@ fn convert_float_to_int<'tcx>(
 /// In case of overflow (when the operand is the minimum value), the operation
 /// will wrap around.
 fn int_abs<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     op: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (op, op_len) = this.project_to_simd(op)?;
-    let (dest, dest_len) = this.project_to_simd(dest)?;
+    let (op, op_len) = ecx.project_to_simd(op)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(op_len, dest_len);
 
-    let zero = ImmTy::from_int(0, op.layout.field(this, 0));
+    let zero = ImmTy::from_int(0, op.layout.field(ecx, 0));
 
     for i in 0..dest_len {
-        let op = this.read_immediate(&this.project_index(&op, i)?)?;
-        let dest = this.project_index(&dest, i)?;
+        let op = ecx.read_immediate(&ecx.project_index(&op, i)?)?;
+        let dest = ecx.project_index(&dest, i)?;
 
-        let lt_zero = this.binary_op(mir::BinOp::Lt, &op, &zero)?;
+        let lt_zero = ecx.binary_op(mir::BinOp::Lt, &op, &zero)?;
         let res =
-            if lt_zero.to_scalar().to_bool()? { this.unary_op(mir::UnOp::Neg, &op)? } else { op };
+            if lt_zero.to_scalar().to_bool()? { ecx.unary_op(mir::UnOp::Neg, &op)? } else { op };
 
-        this.write_immediate(*res, &dest)?;
+        ecx.write_immediate(*res, &dest)?;
     }
 
     interp_ok(())
@@ -776,25 +757,25 @@ fn int_abs<'tcx>(
 /// * The third element is the `op` vector split into chunks, i.e, it's
 ///   type is `[[T; M]; N]` where `T` is the element type of `op`.
 fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     op: &P,
 ) -> InterpResult<'tcx, (u64, u64, P)> {
     let simd_layout = op.layout();
-    let (simd_len, element_ty) = simd_layout.ty.simd_size_and_type(this.tcx.tcx);
+    let (simd_len, element_ty) = simd_layout.ty.simd_size_and_type(ecx.tcx.tcx);
 
     assert_eq!(simd_layout.size.bits() % 128, 0);
     let num_chunks = simd_layout.size.bits() / 128;
     let items_per_chunk = simd_len.strict_div(num_chunks);
 
     // Transmute to `[[T; items_per_chunk]; num_chunks]`
-    let chunked_layout = this
+    let chunked_layout = ecx
         .layout_of(Ty::new_array(
-            this.tcx.tcx,
-            Ty::new_array(this.tcx.tcx, element_ty, items_per_chunk),
+            ecx.tcx.tcx,
+            Ty::new_array(ecx.tcx.tcx, element_ty, items_per_chunk),
             num_chunks,
         ))
         .unwrap();
-    let chunked_op = op.transmute(chunked_layout, this)?;
+    let chunked_op = op.transmute(chunked_layout, ecx)?;
 
     interp_ok((num_chunks, items_per_chunk, chunked_op))
 }
@@ -809,7 +790,7 @@ fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit chunks of `left` and `right`).
 fn horizontal_bin_op<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     which: mir::BinOp,
     saturating: bool,
     left: &OpTy<'tcx>,
@@ -819,15 +800,15 @@ fn horizontal_bin_op<'tcx>(
     assert_eq!(left.layout, dest.layout);
     assert_eq!(right.layout, dest.layout);
 
-    let (num_chunks, items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?;
-    let (_, _, right) = split_simd_to_128bit_chunks(this, right)?;
-    let (_, _, dest) = split_simd_to_128bit_chunks(this, dest)?;
+    let (num_chunks, items_per_chunk, left) = split_simd_to_128bit_chunks(ecx, left)?;
+    let (_, _, right) = split_simd_to_128bit_chunks(ecx, right)?;
+    let (_, _, dest) = split_simd_to_128bit_chunks(ecx, dest)?;
 
     let middle = items_per_chunk / 2;
     for i in 0..num_chunks {
-        let left = this.project_index(&left, i)?;
-        let right = this.project_index(&right, i)?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.project_index(&left, i)?;
+        let right = ecx.project_index(&right, i)?;
+        let dest = ecx.project_index(&dest, i)?;
 
         for j in 0..items_per_chunk {
             // `j` is the index in `dest`
@@ -835,16 +816,16 @@ fn horizontal_bin_op<'tcx>(
             let (k, src) = if j < middle { (j, &left) } else { (j.strict_sub(middle), &right) };
             // `base_i` is the index of the first item of the 2-item chunk in `src`
             let base_i = k.strict_mul(2);
-            let lhs = this.read_immediate(&this.project_index(src, base_i)?)?;
-            let rhs = this.read_immediate(&this.project_index(src, base_i.strict_add(1))?)?;
+            let lhs = ecx.read_immediate(&ecx.project_index(src, base_i)?)?;
+            let rhs = ecx.read_immediate(&ecx.project_index(src, base_i.strict_add(1))?)?;
 
             let res = if saturating {
-                Immediate::from(this.saturating_arith(which, &lhs, &rhs)?)
+                Immediate::from(ecx.saturating_arith(which, &lhs, &rhs)?)
             } else {
-                *this.binary_op(which, &lhs, &rhs)?
+                *ecx.binary_op(which, &lhs, &rhs)?
             };
 
-            this.write_immediate(res, &this.project_index(&dest, j)?)?;
+            ecx.write_immediate(res, &ecx.project_index(&dest, j)?)?;
         }
     }
 
@@ -860,7 +841,7 @@ fn horizontal_bin_op<'tcx>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit blocks of `left` and `right`).
 fn conditional_dot_product<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     imm: &OpTy<'tcx>,
@@ -869,20 +850,20 @@ fn conditional_dot_product<'tcx>(
     assert_eq!(left.layout, dest.layout);
     assert_eq!(right.layout, dest.layout);
 
-    let (num_chunks, items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?;
-    let (_, _, right) = split_simd_to_128bit_chunks(this, right)?;
-    let (_, _, dest) = split_simd_to_128bit_chunks(this, dest)?;
+    let (num_chunks, items_per_chunk, left) = split_simd_to_128bit_chunks(ecx, left)?;
+    let (_, _, right) = split_simd_to_128bit_chunks(ecx, right)?;
+    let (_, _, dest) = split_simd_to_128bit_chunks(ecx, dest)?;
 
-    let element_layout = left.layout.field(this, 0).field(this, 0);
+    let element_layout = left.layout.field(ecx, 0).field(ecx, 0);
     assert!(items_per_chunk <= 4);
 
     // `imm` is a `u8` for SSE4.1 or an `i32` for AVX :/
-    let imm = this.read_scalar(imm)?.to_uint(imm.layout.size)?;
+    let imm = ecx.read_scalar(imm)?.to_uint(imm.layout.size)?;
 
     for i in 0..num_chunks {
-        let left = this.project_index(&left, i)?;
-        let right = this.project_index(&right, i)?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.project_index(&left, i)?;
+        let right = ecx.project_index(&right, i)?;
+        let dest = ecx.project_index(&dest, i)?;
 
         // Calculate dot product
         // Elements are floating point numbers, but we can use `from_int`
@@ -890,22 +871,22 @@ fn conditional_dot_product<'tcx>(
         let mut sum = ImmTy::from_int(0u8, element_layout);
         for j in 0..items_per_chunk {
             if imm & (1 << j.strict_add(4)) != 0 {
-                let left = this.read_immediate(&this.project_index(&left, j)?)?;
-                let right = this.read_immediate(&this.project_index(&right, j)?)?;
+                let left = ecx.read_immediate(&ecx.project_index(&left, j)?)?;
+                let right = ecx.read_immediate(&ecx.project_index(&right, j)?)?;
 
-                let mul = this.binary_op(mir::BinOp::Mul, &left, &right)?;
-                sum = this.binary_op(mir::BinOp::Add, &sum, &mul)?;
+                let mul = ecx.binary_op(mir::BinOp::Mul, &left, &right)?;
+                sum = ecx.binary_op(mir::BinOp::Add, &sum, &mul)?;
             }
         }
 
         // Write to destination (conditioned to imm)
         for j in 0..items_per_chunk {
-            let dest = this.project_index(&dest, j)?;
+            let dest = ecx.project_index(&dest, j)?;
 
             if imm & (1 << j) != 0 {
-                this.write_immediate(*sum, &dest)?;
+                ecx.write_immediate(*sum, &dest)?;
             } else {
-                this.write_scalar(Scalar::from_int(0u8, element_layout.size), &dest)?;
+                ecx.write_scalar(Scalar::from_int(0u8, element_layout.size), &dest)?;
             }
         }
     }
@@ -918,25 +899,25 @@ fn conditional_dot_product<'tcx>(
 /// The first is true when all the bits of `op & mask` are zero.
 /// The second is true when `(op & mask) == mask`
 fn test_bits_masked<'tcx>(
-    this: &crate::MiriInterpCx<'tcx>,
+    ecx: &crate::MiriInterpCx<'tcx>,
     op: &OpTy<'tcx>,
     mask: &OpTy<'tcx>,
 ) -> InterpResult<'tcx, (bool, bool)> {
     assert_eq!(op.layout, mask.layout);
 
-    let (op, op_len) = this.project_to_simd(op)?;
-    let (mask, mask_len) = this.project_to_simd(mask)?;
+    let (op, op_len) = ecx.project_to_simd(op)?;
+    let (mask, mask_len) = ecx.project_to_simd(mask)?;
 
     assert_eq!(op_len, mask_len);
 
     let mut all_zero = true;
     let mut masked_set = true;
     for i in 0..op_len {
-        let op = this.project_index(&op, i)?;
-        let mask = this.project_index(&mask, i)?;
+        let op = ecx.project_index(&op, i)?;
+        let mask = ecx.project_index(&mask, i)?;
 
-        let op = this.read_scalar(&op)?.to_uint(op.layout.size)?;
-        let mask = this.read_scalar(&mask)?.to_uint(mask.layout.size)?;
+        let op = ecx.read_scalar(&op)?.to_uint(op.layout.size)?;
+        let mask = ecx.read_scalar(&mask)?.to_uint(mask.layout.size)?;
         all_zero &= (op & mask) == 0;
         masked_set &= (op & mask) == mask;
     }
@@ -949,27 +930,27 @@ fn test_bits_masked<'tcx>(
 /// The first is true when the highest bit of each element of `op & mask` is zero.
 /// The second is true when the highest bit of each element of `!op & mask` is zero.
 fn test_high_bits_masked<'tcx>(
-    this: &crate::MiriInterpCx<'tcx>,
+    ecx: &crate::MiriInterpCx<'tcx>,
     op: &OpTy<'tcx>,
     mask: &OpTy<'tcx>,
 ) -> InterpResult<'tcx, (bool, bool)> {
     assert_eq!(op.layout, mask.layout);
 
-    let (op, op_len) = this.project_to_simd(op)?;
-    let (mask, mask_len) = this.project_to_simd(mask)?;
+    let (op, op_len) = ecx.project_to_simd(op)?;
+    let (mask, mask_len) = ecx.project_to_simd(mask)?;
 
     assert_eq!(op_len, mask_len);
 
-    let high_bit_offset = op.layout.field(this, 0).size.bits().strict_sub(1);
+    let high_bit_offset = op.layout.field(ecx, 0).size.bits().strict_sub(1);
 
     let mut direct = true;
     let mut negated = true;
     for i in 0..op_len {
-        let op = this.project_index(&op, i)?;
-        let mask = this.project_index(&mask, i)?;
+        let op = ecx.project_index(&op, i)?;
+        let mask = ecx.project_index(&mask, i)?;
 
-        let op = this.read_scalar(&op)?.to_uint(op.layout.size)?;
-        let mask = this.read_scalar(&mask)?.to_uint(mask.layout.size)?;
+        let op = ecx.read_scalar(&op)?.to_uint(op.layout.size)?;
+        let mask = ecx.read_scalar(&mask)?.to_uint(mask.layout.size)?;
         direct &= (op & mask) >> high_bit_offset == 0;
         negated &= (!op & mask) >> high_bit_offset == 0;
     }
@@ -980,30 +961,30 @@ fn test_high_bits_masked<'tcx>(
 /// Conditionally loads from `ptr` according the high bit of each
 /// element of `mask`. `ptr` does not need to be aligned.
 fn mask_load<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     ptr: &OpTy<'tcx>,
     mask: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (mask, mask_len) = this.project_to_simd(mask)?;
-    let (dest, dest_len) = this.project_to_simd(dest)?;
+    let (mask, mask_len) = ecx.project_to_simd(mask)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, mask_len);
 
-    let mask_item_size = mask.layout.field(this, 0).size;
+    let mask_item_size = mask.layout.field(ecx, 0).size;
     let high_bit_offset = mask_item_size.bits().strict_sub(1);
 
-    let ptr = this.read_pointer(ptr)?;
+    let ptr = ecx.read_pointer(ptr)?;
     for i in 0..dest_len {
-        let mask = this.project_index(&mask, i)?;
-        let dest = this.project_index(&dest, i)?;
+        let mask = ecx.project_index(&mask, i)?;
+        let dest = ecx.project_index(&dest, i)?;
 
-        if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 {
-            let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx);
+        if ecx.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 {
+            let ptr = ptr.wrapping_offset(dest.layout.size * i, &ecx.tcx);
             // Unaligned copy, which is what we want.
-            this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?;
+            ecx.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?;
         } else {
-            this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
+            ecx.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?;
         }
     }
 
@@ -1013,31 +994,31 @@ fn mask_load<'tcx>(
 /// Conditionally stores into `ptr` according the high bit of each
 /// element of `mask`. `ptr` does not need to be aligned.
 fn mask_store<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     ptr: &OpTy<'tcx>,
     mask: &OpTy<'tcx>,
     value: &OpTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    let (mask, mask_len) = this.project_to_simd(mask)?;
-    let (value, value_len) = this.project_to_simd(value)?;
+    let (mask, mask_len) = ecx.project_to_simd(mask)?;
+    let (value, value_len) = ecx.project_to_simd(value)?;
 
     assert_eq!(value_len, mask_len);
 
-    let mask_item_size = mask.layout.field(this, 0).size;
+    let mask_item_size = mask.layout.field(ecx, 0).size;
     let high_bit_offset = mask_item_size.bits().strict_sub(1);
 
-    let ptr = this.read_pointer(ptr)?;
+    let ptr = ecx.read_pointer(ptr)?;
     for i in 0..value_len {
-        let mask = this.project_index(&mask, i)?;
-        let value = this.project_index(&value, i)?;
+        let mask = ecx.project_index(&mask, i)?;
+        let value = ecx.project_index(&value, i)?;
 
-        if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 {
+        if ecx.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 {
             // *Non-inbounds* pointer arithmetic to compute the destination.
             // (That's why we can't use a place projection.)
-            let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx);
+            let ptr = ptr.wrapping_offset(value.layout.size * i, &ecx.tcx);
             // Deref the pointer *unaligned*, and do the copy.
-            let dest = this.ptr_to_mplace_unaligned(ptr, value.layout);
-            this.copy_op(&value, &dest)?;
+            let dest = ecx.ptr_to_mplace_unaligned(ptr, value.layout);
+            ecx.copy_op(&value, &dest)?;
         }
     }
 
@@ -1056,7 +1037,7 @@ fn mask_store<'tcx>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit chunks of `left` and `right`).
 fn mpsadbw<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     imm: &OpTy<'tcx>,
@@ -1065,13 +1046,13 @@ fn mpsadbw<'tcx>(
     assert_eq!(left.layout, right.layout);
     assert_eq!(left.layout.size, dest.layout.size);
 
-    let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?;
-    let (_, _, right) = split_simd_to_128bit_chunks(this, right)?;
-    let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?;
+    let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(ecx, left)?;
+    let (_, _, right) = split_simd_to_128bit_chunks(ecx, right)?;
+    let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(ecx, dest)?;
 
     assert_eq!(op_items_per_chunk, dest_items_per_chunk.strict_mul(2));
 
-    let imm = this.read_scalar(imm)?.to_uint(imm.layout.size)?;
+    let imm = ecx.read_scalar(imm)?.to_uint(imm.layout.size)?;
     // Bit 2 of `imm` specifies the offset for indices of `left`.
     // The offset is 0 when the bit is 0 or 4 when the bit is 1.
     let left_offset = u64::try_from((imm >> 2) & 1).unwrap().strict_mul(4);
@@ -1080,23 +1061,23 @@ fn mpsadbw<'tcx>(
     let right_offset = u64::try_from(imm & 0b11).unwrap().strict_mul(4);
 
     for i in 0..num_chunks {
-        let left = this.project_index(&left, i)?;
-        let right = this.project_index(&right, i)?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.project_index(&left, i)?;
+        let right = ecx.project_index(&right, i)?;
+        let dest = ecx.project_index(&dest, i)?;
 
         for j in 0..dest_items_per_chunk {
             let left_offset = left_offset.strict_add(j);
             let mut res: u16 = 0;
             for k in 0..4 {
-                let left = this
-                    .read_scalar(&this.project_index(&left, left_offset.strict_add(k))?)?
+                let left = ecx
+                    .read_scalar(&ecx.project_index(&left, left_offset.strict_add(k))?)?
                     .to_u8()?;
-                let right = this
-                    .read_scalar(&this.project_index(&right, right_offset.strict_add(k))?)?
+                let right = ecx
+                    .read_scalar(&ecx.project_index(&right, right_offset.strict_add(k))?)?
                     .to_u8()?;
                 res = res.strict_add(left.abs_diff(right).into());
             }
-            this.write_scalar(Scalar::from_u16(res), &this.project_index(&dest, j)?)?;
+            ecx.write_scalar(Scalar::from_u16(res), &ecx.project_index(&dest, j)?)?;
         }
     }
 
@@ -1111,22 +1092,22 @@ fn mpsadbw<'tcx>(
 /// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16>
 /// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16>
 fn pmulhrsw<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> 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)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (right, right_len) = ecx.project_to_simd(right)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, left_len);
     assert_eq!(dest_len, right_len);
 
     for i in 0..dest_len {
-        let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?;
-        let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.read_scalar(&ecx.project_index(&left, i)?)?.to_i16()?;
+        let right = ecx.read_scalar(&ecx.project_index(&right, i)?)?.to_i16()?;
+        let dest = ecx.project_index(&dest, i)?;
 
         let res = (i32::from(left).strict_mul(right.into()) >> 14).strict_add(1) >> 1;
 
@@ -1135,7 +1116,7 @@ fn pmulhrsw<'tcx>(
         #[expect(clippy::cast_possible_truncation)]
         let res = res as i16;
 
-        this.write_scalar(Scalar::from_i16(res), &dest)?;
+        ecx.write_scalar(Scalar::from_i16(res), &dest)?;
     }
 
     interp_ok(())
@@ -1152,7 +1133,7 @@ fn pmulhrsw<'tcx>(
 ///
 /// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128>
 fn pclmulqdq<'tcx>(
-    this: &mut MiriInterpCx<'tcx>,
+    ecx: &mut MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     imm8: &OpTy<'tcx>,
@@ -1166,14 +1147,14 @@ fn pclmulqdq<'tcx>(
     // Transmute the input into arrays of `[u64; len]`.
     // Transmute the output into an array of `[u128, len / 2]`.
 
-    let src_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, len))?;
-    let dest_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u128, len / 2))?;
+    let src_layout = ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u64, len))?;
+    let dest_layout = ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u128, len / 2))?;
 
-    let left = left.transmute(src_layout, this)?;
-    let right = right.transmute(src_layout, this)?;
-    let dest = dest.transmute(dest_layout, this)?;
+    let left = left.transmute(src_layout, ecx)?;
+    let right = right.transmute(src_layout, ecx)?;
+    let dest = dest.transmute(dest_layout, ecx)?;
 
-    let imm8 = this.read_scalar(imm8)?.to_u8()?;
+    let imm8 = ecx.read_scalar(imm8)?.to_u8()?;
 
     for i in 0..(len / 2) {
         let lo = i.strict_mul(2);
@@ -1181,11 +1162,11 @@ fn pclmulqdq<'tcx>(
 
         // select the 64-bit integer from left that the user specified (low or high)
         let index = if (imm8 & 0x01) == 0 { lo } else { hi };
-        let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u64()?;
+        let left = ecx.read_scalar(&ecx.project_index(&left, index)?)?.to_u64()?;
 
         // select the 64-bit integer from right that the user specified (low or high)
         let index = if (imm8 & 0x10) == 0 { lo } else { hi };
-        let right = this.read_scalar(&this.project_index(&right, index)?)?.to_u64()?;
+        let right = ecx.read_scalar(&ecx.project_index(&right, index)?)?.to_u64()?;
 
         // Perform carry-less multiplication.
         //
@@ -1203,8 +1184,8 @@ fn pclmulqdq<'tcx>(
             }
         }
 
-        let dest = this.project_index(&dest, i)?;
-        this.write_scalar(Scalar::from_u128(result), &dest)?;
+        let dest = ecx.project_index(&dest, i)?;
+        ecx.write_scalar(Scalar::from_u128(result), &dest)?;
     }
 
     interp_ok(())
@@ -1218,7 +1199,7 @@ fn pclmulqdq<'tcx>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit chunks of `left` and `right`).
 fn pack_generic<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
@@ -1227,28 +1208,28 @@ fn pack_generic<'tcx>(
     assert_eq!(left.layout, right.layout);
     assert_eq!(left.layout.size, dest.layout.size);
 
-    let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(this, left)?;
-    let (_, _, right) = split_simd_to_128bit_chunks(this, right)?;
-    let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(this, dest)?;
+    let (num_chunks, op_items_per_chunk, left) = split_simd_to_128bit_chunks(ecx, left)?;
+    let (_, _, right) = split_simd_to_128bit_chunks(ecx, right)?;
+    let (_, dest_items_per_chunk, dest) = split_simd_to_128bit_chunks(ecx, dest)?;
 
     assert_eq!(dest_items_per_chunk, op_items_per_chunk.strict_mul(2));
 
     for i in 0..num_chunks {
-        let left = this.project_index(&left, i)?;
-        let right = this.project_index(&right, i)?;
-        let dest = this.project_index(&dest, i)?;
+        let left = ecx.project_index(&left, i)?;
+        let right = ecx.project_index(&right, i)?;
+        let dest = ecx.project_index(&dest, i)?;
 
         for j in 0..op_items_per_chunk {
-            let left = this.read_scalar(&this.project_index(&left, j)?)?;
-            let right = this.read_scalar(&this.project_index(&right, j)?)?;
-            let left_dest = this.project_index(&dest, j)?;
-            let right_dest = this.project_index(&dest, j.strict_add(op_items_per_chunk))?;
+            let left = ecx.read_scalar(&ecx.project_index(&left, j)?)?;
+            let right = ecx.read_scalar(&ecx.project_index(&right, j)?)?;
+            let left_dest = ecx.project_index(&dest, j)?;
+            let right_dest = ecx.project_index(&dest, j.strict_add(op_items_per_chunk))?;
 
             let left_res = f(left)?;
             let right_res = f(right)?;
 
-            this.write_scalar(left_res, &left_dest)?;
-            this.write_scalar(right_res, &right_dest)?;
+            ecx.write_scalar(left_res, &left_dest)?;
+            ecx.write_scalar(right_res, &right_dest)?;
         }
     }
 
@@ -1262,12 +1243,12 @@ fn pack_generic<'tcx>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit chunks of `left` and `right`).
 fn packsswb<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    pack_generic(this, left, right, dest, |op| {
+    pack_generic(ecx, 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 });
         interp_ok(Scalar::from_i8(res))
@@ -1281,12 +1262,12 @@ fn packsswb<'tcx>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit chunks of `left` and `right`).
 fn packuswb<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    pack_generic(this, left, right, dest, |op| {
+    pack_generic(ecx, left, right, dest, |op| {
         let op = op.to_i16()?;
         let res = u8::try_from(op).unwrap_or(if op < 0 { 0 } else { u8::MAX });
         interp_ok(Scalar::from_u8(res))
@@ -1300,12 +1281,12 @@ fn packuswb<'tcx>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit chunks of `left` and `right`).
 fn packssdw<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    pack_generic(this, left, right, dest, |op| {
+    pack_generic(ecx, 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 });
         interp_ok(Scalar::from_i16(res))
@@ -1319,12 +1300,12 @@ fn packssdw<'tcx>(
 /// the is i-th 128-bit chunk of `dest` is calculated with the i-th
 /// 128-bit chunks of `left` and `right`).
 fn packusdw<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx, ()> {
-    pack_generic(this, left, right, dest, |op| {
+    pack_generic(ecx, left, right, dest, |op| {
         let op = op.to_i32()?;
         let res = u16::try_from(op).unwrap_or(if op < 0 { 0 } else { u16::MAX });
         interp_ok(Scalar::from_u16(res))
@@ -1336,27 +1317,27 @@ fn packusdw<'tcx>(
 /// is written to the corresponding output element.
 /// In other words, multiplies `left` with `right.signum()`.
 fn psign<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     left: &OpTy<'tcx>,
     right: &OpTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
 ) -> 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)?;
+    let (left, left_len) = ecx.project_to_simd(left)?;
+    let (right, right_len) = ecx.project_to_simd(right)?;
+    let (dest, dest_len) = ecx.project_to_simd(dest)?;
 
     assert_eq!(dest_len, left_len);
     assert_eq!(dest_len, right_len);
 
     for i in 0..dest_len {
-        let dest = this.project_index(&dest, i)?;
-        let left = this.read_immediate(&this.project_index(&left, i)?)?;
-        let right = this.read_scalar(&this.project_index(&right, i)?)?.to_int(dest.layout.size)?;
+        let dest = ecx.project_index(&dest, i)?;
+        let left = ecx.read_immediate(&ecx.project_index(&left, i)?)?;
+        let right = ecx.read_scalar(&ecx.project_index(&right, i)?)?.to_int(dest.layout.size)?;
 
         let res =
-            this.binary_op(mir::BinOp::Mul, &left, &ImmTy::from_int(right.signum(), dest.layout))?;
+            ecx.binary_op(mir::BinOp::Mul, &left, &ImmTy::from_int(right.signum(), dest.layout))?;
 
-        this.write_immediate(*res, &dest)?;
+        ecx.write_immediate(*res, &dest)?;
     }
 
     interp_ok(())
@@ -1366,7 +1347,7 @@ fn psign<'tcx>(
 /// of `op` and returns both the sum and the overflow bit. `op` is expected to be
 /// either one of `mir::BinOp::AddWithOverflow` and `mir::BinOp::SubWithOverflow`.
 fn carrying_add<'tcx>(
-    this: &mut crate::MiriInterpCx<'tcx>,
+    ecx: &mut crate::MiriInterpCx<'tcx>,
     cb_in: &OpTy<'tcx>,
     a: &OpTy<'tcx>,
     b: &OpTy<'tcx>,
@@ -1374,13 +1355,13 @@ fn carrying_add<'tcx>(
 ) -> InterpResult<'tcx, (ImmTy<'tcx>, Scalar)> {
     assert!(op == mir::BinOp::AddWithOverflow || op == mir::BinOp::SubWithOverflow);
 
-    let cb_in = this.read_scalar(cb_in)?.to_u8()? != 0;
-    let a = this.read_immediate(a)?;
-    let b = this.read_immediate(b)?;
+    let cb_in = ecx.read_scalar(cb_in)?.to_u8()? != 0;
+    let a = ecx.read_immediate(a)?;
+    let b = ecx.read_immediate(b)?;
 
-    let (sum, overflow1) = this.binary_op(op, &a, &b)?.to_pair(this);
+    let (sum, overflow1) = ecx.binary_op(op, &a, &b)?.to_pair(ecx);
     let (sum, overflow2) =
-        this.binary_op(op, &sum, &ImmTy::from_uint(cb_in, a.layout))?.to_pair(this);
+        ecx.binary_op(op, &sum, &ImmTy::from_uint(cb_in, a.layout))?.to_pair(ecx);
     let cb_out = overflow1.to_scalar().to_bool()? | overflow2.to_scalar().to_bool()?;
 
     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 964204127d9..f18ff1ec253 100644
--- a/src/tools/miri/src/shims/x86/sha.rs
+++ b/src/tools/miri/src/shims/x86/sha.rs
@@ -23,27 +23,27 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Prefix should have already been checked.
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap();
 
-        fn read<'c>(this: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
+        fn read<'c>(ecx: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
             let mut res = [0; 4];
             // We reverse the order because x86 is little endian but the copied implementation uses
             // big endian.
             for (i, dst) in res.iter_mut().rev().enumerate() {
-                let projected = &this.project_index(reg, i.try_into().unwrap())?;
-                *dst = this.read_scalar(projected)?.to_u32()?
+                let projected = &ecx.project_index(reg, i.try_into().unwrap())?;
+                *dst = ecx.read_scalar(projected)?.to_u32()?
             }
             interp_ok(res)
         }
 
         fn write<'c>(
-            this: &mut MiriInterpCx<'c>,
+            ecx: &mut MiriInterpCx<'c>,
             dest: &MPlaceTy<'c>,
             val: [u32; 4],
         ) -> InterpResult<'c, ()> {
             // We reverse the order because x86 is little endian but the copied implementation uses
             // big endian.
             for (i, part) in val.into_iter().rev().enumerate() {
-                let projected = &this.project_index(dest, i.try_into().unwrap())?;
-                this.write_scalar(Scalar::from_u32(part), projected)?;
+                let projected = &ecx.project_index(dest, i.try_into().unwrap())?;
+                ecx.write_scalar(Scalar::from_u32(part), projected)?;
             }
             interp_ok(())
         }
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index cc7cfab5041..0b058a9911e 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -70,7 +70,7 @@ const USE_SIGNED: u8 = 2;
 /// For more information, see the Intel Software Developer's Manual, Vol. 2b, Chapter 4.1.
 #[expect(clippy::arithmetic_side_effects)]
 fn compare_strings<'tcx>(
-    this: &mut MiriInterpCx<'tcx>,
+    ecx: &mut MiriInterpCx<'tcx>,
     str1: &OpTy<'tcx>,
     str2: &OpTy<'tcx>,
     len: Option<(u64, u64)>,
@@ -80,8 +80,8 @@ fn compare_strings<'tcx>(
     let (len1, len2) = if let Some(t) = len {
         t
     } else {
-        let len1 = implicit_len(this, str1, imm)?.unwrap_or(default_len);
-        let len2 = implicit_len(this, str2, imm)?.unwrap_or(default_len);
+        let len1 = implicit_len(ecx, str1, imm)?.unwrap_or(default_len);
+        let len2 = implicit_len(ecx, str2, imm)?.unwrap_or(default_len);
         (len1, len2)
     };
 
@@ -90,12 +90,12 @@ fn compare_strings<'tcx>(
         0 => {
             // Equal any: Checks which characters of `str2` are inside `str1`.
             for i in 0..len2 {
-                let ch2 = this.read_immediate(&this.project_index(str2, i)?)?;
+                let ch2 = ecx.read_immediate(&ecx.project_index(str2, i)?)?;
 
                 for j in 0..len1 {
-                    let ch1 = this.read_immediate(&this.project_index(str1, j)?)?;
+                    let ch1 = ecx.read_immediate(&ecx.project_index(str1, j)?)?;
 
-                    let eq = this.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
+                    let eq = ecx.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
                     if eq.to_scalar().to_bool()? {
                         result |= 1 << i;
                         break;
@@ -119,9 +119,9 @@ fn compare_strings<'tcx>(
 
             for i in 0..len2 {
                 for j in (0..len1).step_by(2) {
-                    let ch2 = get_ch(this.read_scalar(&this.project_index(str2, i)?)?)?;
-                    let ch1_1 = get_ch(this.read_scalar(&this.project_index(str1, j)?)?)?;
-                    let ch1_2 = get_ch(this.read_scalar(&this.project_index(str1, j + 1)?)?)?;
+                    let ch2 = get_ch(ecx.read_scalar(&ecx.project_index(str2, i)?)?)?;
+                    let ch1_1 = get_ch(ecx.read_scalar(&ecx.project_index(str1, j)?)?)?;
+                    let ch1_2 = get_ch(ecx.read_scalar(&ecx.project_index(str1, j + 1)?)?)?;
 
                     if ch1_1 <= ch2 && ch2 <= ch1_2 {
                         result |= 1 << i;
@@ -135,9 +135,9 @@ fn compare_strings<'tcx>(
             result ^= (1 << len1.max(len2)) - 1;
 
             for i in 0..len1.min(len2) {
-                let ch1 = this.read_immediate(&this.project_index(str1, i)?)?;
-                let ch2 = this.read_immediate(&this.project_index(str2, i)?)?;
-                let eq = this.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
+                let ch1 = ecx.read_immediate(&ecx.project_index(str1, i)?)?;
+                let ch2 = ecx.read_immediate(&ecx.project_index(str2, i)?)?;
+                let eq = ecx.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
                 result |= i32::from(eq.to_scalar().to_bool()?) << i;
             }
         }
@@ -159,9 +159,9 @@ fn compare_strings<'tcx>(
                         if k >= default_len {
                             break;
                         } else {
-                            let ch1 = this.read_immediate(&this.project_index(str1, j)?)?;
-                            let ch2 = this.read_immediate(&this.project_index(str2, k)?)?;
-                            let ne = this.binary_op(mir::BinOp::Ne, &ch1, &ch2)?;
+                            let ch1 = ecx.read_immediate(&ecx.project_index(str1, j)?)?;
+                            let ch2 = ecx.read_immediate(&ecx.project_index(str2, k)?)?;
+                            let ne = ecx.binary_op(mir::BinOp::Ne, &ch1, &ch2)?;
 
                             if ne.to_scalar().to_bool()? {
                                 result &= !(1 << i);
@@ -198,16 +198,16 @@ fn compare_strings<'tcx>(
 /// corresponding to the x86 128-bit integer SIMD type.
 fn deconstruct_args<'tcx>(
     unprefixed_name: &str,
-    this: &mut MiriInterpCx<'tcx>,
+    ecx: &mut MiriInterpCx<'tcx>,
     link_name: Symbol,
     abi: ExternAbi,
     args: &[OpTy<'tcx>],
 ) -> InterpResult<'tcx, (OpTy<'tcx>, OpTy<'tcx>, Option<(u64, u64)>, u8)> {
-    let array_layout_fn = |this: &mut MiriInterpCx<'tcx>, imm: u8| {
+    let array_layout_fn = |ecx: &mut MiriInterpCx<'tcx>, imm: u8| {
         if imm & USE_WORDS != 0 {
-            this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u16, 8))
+            ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u16, 8))
         } else {
-            this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u8, 16))
+            ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u8, 16))
         }
     };
 
@@ -223,26 +223,26 @@ fn deconstruct_args<'tcx>(
 
     if is_explicit {
         let [str1, len1, str2, len2, imm] =
-            this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
-        let imm = this.read_scalar(imm)?.to_u8()?;
+            ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
+        let imm = ecx.read_scalar(imm)?.to_u8()?;
 
         let default_len = default_len::<u32>(imm);
-        let len1 = u64::from(this.read_scalar(len1)?.to_u32()?.min(default_len));
-        let len2 = u64::from(this.read_scalar(len2)?.to_u32()?.min(default_len));
+        let len1 = u64::from(ecx.read_scalar(len1)?.to_u32()?.min(default_len));
+        let len2 = u64::from(ecx.read_scalar(len2)?.to_u32()?.min(default_len));
 
-        let array_layout = array_layout_fn(this, imm)?;
-        let str1 = str1.transmute(array_layout, this)?;
-        let str2 = str2.transmute(array_layout, this)?;
+        let array_layout = array_layout_fn(ecx, imm)?;
+        let str1 = str1.transmute(array_layout, ecx)?;
+        let str2 = str2.transmute(array_layout, ecx)?;
 
         interp_ok((str1, str2, Some((len1, len2)), imm))
     } else {
         let [str1, str2, imm] =
-            this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
-        let imm = this.read_scalar(imm)?.to_u8()?;
+            ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
+        let imm = ecx.read_scalar(imm)?.to_u8()?;
 
-        let array_layout = array_layout_fn(this, imm)?;
-        let str1 = str1.transmute(array_layout, this)?;
-        let str2 = str2.transmute(array_layout, this)?;
+        let array_layout = array_layout_fn(ecx, imm)?;
+        let str1 = str1.transmute(array_layout, ecx)?;
+        let str2 = str2.transmute(array_layout, ecx)?;
 
         interp_ok((str1, str2, None, imm))
     }
@@ -251,16 +251,16 @@ fn deconstruct_args<'tcx>(
 /// Calculate the c-style string length for a given string `str`.
 /// The string is either a length 16 array of bytes a length 8 array of two-byte words.
 fn implicit_len<'tcx>(
-    this: &mut MiriInterpCx<'tcx>,
+    ecx: &mut MiriInterpCx<'tcx>,
     str: &OpTy<'tcx>,
     imm: u8,
 ) -> InterpResult<'tcx, Option<u64>> {
     let mut result = None;
-    let zero = ImmTy::from_int(0, str.layout.field(this, 0));
+    let zero = ImmTy::from_int(0, str.layout.field(ecx, 0));
 
     for i in 0..default_len::<u64>(imm) {
-        let ch = this.read_immediate(&this.project_index(str, i)?)?;
-        let is_zero = this.binary_op(mir::BinOp::Eq, &ch, &zero)?;
+        let ch = ecx.read_immediate(&ecx.project_index(str, i)?)?;
+        let is_zero = ecx.binary_op(mir::BinOp::Eq, &ch, &zero)?;
         if is_zero.to_scalar().to_bool()? {
             result = Some(i);
             break;
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
new file mode 100644
index 00000000000..65d29b2c6ba
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
@@ -0,0 +1,65 @@
+//@only-target: linux
+//~^ERROR: deadlocked
+//~^^ERROR: deadlocked
+//@compile-flags: -Zmiri-preemption-rate=0
+//@error-in-other-file: deadlock
+
+use std::thread;
+
+// Test the behaviour of a thread being blocked on an eventfd read, get unblocked, and then
+// get blocked again.
+
+// The expected execution is
+// 1. Thread 1 blocks.
+// 2. Thread 2 blocks.
+// 3. Thread 3 unblocks both thread 1 and thread 2.
+// 4. Thread 1 reads.
+// 5. Thread 2's `read` deadlocked.
+
+fn main() {
+    // eventfd write will block when EFD_NONBLOCK flag is clear
+    // and the addition caused counter to exceed u64::MAX - 1.
+    let flags = libc::EFD_CLOEXEC;
+    let fd = unsafe { libc::eventfd(0, flags) };
+
+    let thread1 = thread::spawn(move || {
+        thread::park();
+        let mut buf: [u8; 8] = [0; 8];
+        // This read will block initially.
+        let res: i64 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 8).try_into().unwrap() };
+        assert_eq!(res, 8);
+        let counter = u64::from_ne_bytes(buf);
+        assert_eq!(counter, 1_u64);
+    });
+
+    let thread2 = thread::spawn(move || {
+        thread::park();
+        let mut buf: [u8; 8] = [0; 8];
+        // This read will block initially, then get unblocked by thread3, then get blocked again
+        // because the `read` in thread1 executes first and set the counter to 0 again.
+        let res: i64 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 8).try_into().unwrap() };
+        //~^ERROR: deadlocked
+        assert_eq!(res, 8);
+        let counter = u64::from_ne_bytes(buf);
+        assert_eq!(counter, 1_u64);
+    });
+
+    let thread3 = thread::spawn(move || {
+        thread::park();
+        let sized_8_data = 1_u64.to_ne_bytes();
+        // Write 1 to the counter, so both thread1 and thread2 will unblock.
+        let res: i64 = unsafe {
+            libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+        };
+        // Make sure that write is successful.
+        assert_eq!(res, 8);
+    });
+
+    thread1.thread().unpark();
+    thread2.thread().unpark();
+    thread3.thread().unpark();
+
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+    thread3.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr
new file mode 100644
index 00000000000..bb235345c5e
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr
@@ -0,0 +1,41 @@
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC
+   |
+LL |     thread2.join().unwrap();
+   |     ^^^^^^^^^^^^^^
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC
+   |
+LL |         let res: i64 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 8).try_into().unwrap() };
+   |                                                                          ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside closure at tests/fail-dep/libc/eventfd_block_read_twice.rs:LL:CC
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
new file mode 100644
index 00000000000..f9d34d2fb58
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
@@ -0,0 +1,71 @@
+//@only-target: linux
+//~^ERROR: deadlocked
+//~^^ERROR: deadlocked
+//@compile-flags: -Zmiri-preemption-rate=0
+//@error-in-other-file: deadlock
+
+use std::thread;
+
+// Test the behaviour of a thread being blocked on an eventfd `write`, get unblocked, and then
+// get blocked again.
+
+// The expected execution is
+// 1. Thread 1 blocks.
+// 2. Thread 2 blocks.
+// 3. Thread 3 unblocks both thread 1 and thread 2.
+// 4. Thread 1 writes u64::MAX.
+// 5. Thread 2's `write` deadlocked.
+fn main() {
+    // eventfd write will block when EFD_NONBLOCK flag is clear
+    // and the addition caused counter to exceed u64::MAX - 1.
+    let flags = libc::EFD_CLOEXEC;
+    let fd = unsafe { libc::eventfd(0, flags) };
+    // Write u64 - 1, so the all subsequent write will block.
+    let sized_8_data: [u8; 8] = (u64::MAX - 1).to_ne_bytes();
+    let res: i64 = unsafe {
+        libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+    };
+    assert_eq!(res, 8);
+
+    let thread1 = thread::spawn(move || {
+        thread::park();
+        let sized_8_data = (u64::MAX - 1).to_ne_bytes();
+        let res: i64 = unsafe {
+            libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+        };
+        // Make sure that write is successful.
+        assert_eq!(res, 8);
+    });
+
+    let thread2 = thread::spawn(move || {
+        thread::park();
+        let sized_8_data = (u64::MAX - 1).to_ne_bytes();
+        // Write u64::MAX - 1, so the all subsequent write will block.
+        let res: i64 = unsafe {
+            // This `write` will initially blocked, then get unblocked by thread3, then get blocked again
+            // because the `write` in thread1 executes first.
+            libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+            //~^ERROR: deadlocked
+        };
+        // Make sure that write is successful.
+        assert_eq!(res, 8);
+    });
+
+    let thread3 = thread::spawn(move || {
+        thread::park();
+        let mut buf: [u8; 8] = [0; 8];
+        // This will unblock both `write` in thread1 and thread2.
+        let res: i64 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 8).try_into().unwrap() };
+        assert_eq!(res, 8);
+        let counter = u64::from_ne_bytes(buf);
+        assert_eq!(counter, (u64::MAX - 1));
+    });
+
+    thread1.thread().unpark();
+    thread2.thread().unpark();
+    thread3.thread().unpark();
+
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+    thread3.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr
new file mode 100644
index 00000000000..d9163a5748c
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr
@@ -0,0 +1,41 @@
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC
+   |
+LL |     thread2.join().unwrap();
+   |     ^^^^^^^^^^^^^^
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC
+   |
+LL |             libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+   |                                                                            ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside closure at tests/fail-dep/libc/eventfd_block_write_twice.rs:LL:CC
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
new file mode 100644
index 00000000000..7f5ec477e19
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
@@ -0,0 +1,96 @@
+//@compile-flags: -Zmiri-preemption-rate=0
+//~^ERROR: deadlocked
+//~^^ERROR: deadlocked
+//@only-target: linux
+//@error-in-other-file: deadlock
+
+use std::convert::TryInto;
+use std::thread;
+use std::thread::spawn;
+
+// Using `as` cast since `EPOLLET` wraps around
+const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _;
+
+#[track_caller]
+fn check_epoll_wait<const N: usize>(
+    epfd: i32,
+    expected_notifications: &[(u32, u64)],
+    timeout: i32,
+) {
+    let epoll_event = libc::epoll_event { events: 0, u64: 0 };
+    let mut array: [libc::epoll_event; N] = [epoll_event; N];
+    let maxsize = N;
+    let array_ptr = array.as_mut_ptr();
+    let res = unsafe { libc::epoll_wait(epfd, array_ptr, maxsize.try_into().unwrap(), timeout) };
+    if res < 0 {
+        panic!("epoll_wait failed: {}", std::io::Error::last_os_error());
+    }
+    assert_eq!(
+        res,
+        expected_notifications.len().try_into().unwrap(),
+        "got wrong number of notifications"
+    );
+    let slice = unsafe { std::slice::from_raw_parts(array_ptr, res.try_into().unwrap()) };
+    for (return_event, expected_event) in slice.iter().zip(expected_notifications.iter()) {
+        let event = return_event.events;
+        let data = return_event.u64;
+        assert_eq!(event, expected_event.0, "got wrong events");
+        assert_eq!(data, expected_event.1, "got wrong data");
+    }
+}
+
+// Test if only one thread is unblocked if multiple threads blocked on same epfd.
+// Expected execution:
+// 1. Thread 2 blocks.
+// 2. Thread 3 blocks.
+// 3. Thread 1 unblocks thread 3.
+// 4. Thread 2 deadlocks.
+fn main() {
+    // Create an epoll instance.
+    let epfd = unsafe { libc::epoll_create1(0) };
+    assert_ne!(epfd, -1);
+
+    // Create a socketpair instance.
+    let mut fds = [-1, -1];
+    let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+
+    // Register one side of the socketpair with epoll.
+    let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
+    let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
+    assert_eq!(res, 0);
+
+    // epoll_wait to clear notification.
+    let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
+    let expected_value = fds[0] as u64;
+    check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0);
+
+    let thread1 = spawn(move || {
+        thread::park();
+        let data = "abcde".as_bytes().as_ptr();
+        let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+        assert_eq!(res, 5);
+    });
+
+    let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
+    let expected_value = fds[0] as u64;
+    let thread2 = spawn(move || {
+        thread::park();
+        check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], -1);
+        //~^ERROR: deadlocked
+    });
+    let thread3 = spawn(move || {
+        thread::park();
+        check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], -1);
+    });
+
+    thread2.thread().unpark();
+    thread::yield_now();
+    thread3.thread().unpark();
+    thread::yield_now();
+    thread1.thread().unpark();
+
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+    thread3.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr
new file mode 100644
index 00000000000..010dabc1364
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr
@@ -0,0 +1,41 @@
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC
+   |
+LL |     thread2.join().unwrap();
+   |     ^^^^^^^^^^^^^^
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC
+   |
+LL |         check_epoll_wait::<TAG>(epfd, &[(expected_event, expected_value)], -1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside closure at tests/fail-dep/libc/libc_epoll_block_two_thread.rs:LL:CC
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs
deleted file mode 100644
index 0212a63bd0f..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@only-target: linux
-fn main() {
-    // eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0.
-    // This will pass when blocking is implemented.
-    let flags = libc::EFD_CLOEXEC;
-    let fd = unsafe { libc::eventfd(0, flags) };
-    let mut buf: [u8; 8] = [0; 8];
-    let _res: i32 = unsafe {
-        libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap() //~ERROR: blocking is unsupported
-    };
-}
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr
deleted file mode 100644
index aff30c81ebd..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: unsupported operation: eventfd: blocking is unsupported
-  --> tests/fail-dep/libc/libc_eventfd_read_block.rs:LL:CC
-   |
-LL |         libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap()
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported
-   |
-   = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
-   = note: BACKTRACE:
-   = note: inside `main` at tests/fail-dep/libc/libc_eventfd_read_block.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/libc_eventfd_write_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs
deleted file mode 100644
index ed6ad466901..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-//@only-target: linux
-fn main() {
-    // eventfd write will block when EFD_NONBLOCK flag is clear
-    // and the addition caused counter to exceed u64::MAX - 1.
-    // This will pass when blocking is implemented.
-    let flags = libc::EFD_CLOEXEC;
-    let fd = unsafe { libc::eventfd(0, flags) };
-    // Write u64 - 1.
-    let mut sized_8_data: [u8; 8] = (u64::MAX - 1).to_ne_bytes();
-    let res: i64 = unsafe {
-        libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
-    };
-    assert_eq!(res, 8);
-
-    // Write 1.
-    sized_8_data = 1_u64.to_ne_bytes();
-    // Write 1 to the counter.
-    let _res: i64 = unsafe {
-        libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() //~ERROR: blocking is unsupported
-    };
-}
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr
deleted file mode 100644
index 2b606605794..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: unsupported operation: eventfd: blocking is unsupported
-  --> tests/fail-dep/libc/libc_eventfd_write_block.rs:LL:CC
-   |
-LL |         libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported
-   |
-   = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
-   = note: BACKTRACE:
-   = note: inside `main` at tests/fail-dep/libc/libc_eventfd_write_block.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/tree_borrows/write-during-2phase.rs b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.rs
index a47bb671e32..a2e8a533c43 100644
--- a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.rs
+++ b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.rs
@@ -8,8 +8,8 @@
 
 struct Foo(u64);
 impl Foo {
-    #[rustfmt::skip] // rustfmt is wrong about which line contains an error
-    fn add(&mut self, n: u64) -> u64 { //~ ERROR: /reborrow through .* is forbidden/
+    fn add(&mut self, n: u64) -> u64 {
+        //~^ ERROR: /reborrow through .* is forbidden/
         self.0 + n
     }
 }
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
index c92d9c3fe70..dd9c0eb0b54 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
@@ -1,5 +1,5 @@
 //@only-target: linux
-// test_race depends on a deterministic schedule.
+// test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule.
 //@compile-flags: -Zmiri-preemption-rate=0
 
 // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
@@ -11,6 +11,9 @@ fn main() {
     test_read_write();
     test_race();
     test_syscall();
+    test_blocking_read();
+    test_blocking_write();
+    test_two_threads_blocked_on_eventfd();
 }
 
 fn read_bytes<const N: usize>(fd: i32, buf: &mut [u8; N]) -> i32 {
@@ -118,3 +121,117 @@ fn test_syscall() {
     let fd = unsafe { libc::syscall(libc::SYS_eventfd2, initval, flags) };
     assert_ne!(fd, -1);
 }
+
+// This test will block on eventfd read then get unblocked by `write`.
+fn test_blocking_read() {
+    // eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0.
+    let flags = libc::EFD_CLOEXEC;
+    let fd = unsafe { libc::eventfd(0, flags) };
+    let thread1 = thread::spawn(move || {
+        let mut buf: [u8; 8] = [0; 8];
+        // This will block.
+        let res = read_bytes(fd, &mut buf);
+        // read returns number of bytes has been read, which is always 8.
+        assert_eq!(res, 8);
+        let counter = u64::from_ne_bytes(buf);
+        assert_eq!(counter, 1);
+    });
+    let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
+    // Pass control to thread1 so it can block on eventfd `read`.
+    thread::yield_now();
+    // Write 1 to the counter to unblock thread1.
+    let res = write_bytes(fd, sized_8_data);
+    assert_eq!(res, 8);
+    thread1.join().unwrap();
+}
+
+/// This test will block on eventfd `write` then get unblocked by `read`.
+fn test_blocking_write() {
+    // eventfd write will block when EFD_NONBLOCK flag is clear
+    // and the addition caused counter to exceed u64::MAX - 1.
+    let flags = libc::EFD_CLOEXEC;
+    let fd = unsafe { libc::eventfd(0, flags) };
+    // Write u64 - 1, so the all subsequent write will block.
+    let sized_8_data: [u8; 8] = (u64::MAX - 1).to_ne_bytes();
+    let res: i64 = unsafe {
+        libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+    };
+    assert_eq!(res, 8);
+
+    let thread1 = thread::spawn(move || {
+        let sized_8_data = 1_u64.to_ne_bytes();
+        // Write 1 to the counter, this will block.
+        let res: i64 = unsafe {
+            libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+        };
+        // Make sure that write is successful.
+        assert_eq!(res, 8);
+    });
+    let mut buf: [u8; 8] = [0; 8];
+    // Pass control to thread1 so it can block on eventfd `write`.
+    thread::yield_now();
+    // This will unblock previously blocked eventfd read.
+    let res = read_bytes(fd, &mut buf);
+    // read returns number of bytes has been read, which is always 8.
+    assert_eq!(res, 8);
+    let counter = u64::from_ne_bytes(buf);
+    assert_eq!(counter, (u64::MAX - 1));
+    thread1.join().unwrap();
+}
+
+// Test two threads blocked on eventfd.
+// Expected behaviour:
+// 1. thread1 and thread2 both blocked on `write`.
+// 2. thread3 unblocks both thread1 and thread2
+// 3. The write in thread1 and thread2 return successfully.
+fn test_two_threads_blocked_on_eventfd() {
+    // eventfd write will block when EFD_NONBLOCK flag is clear
+    // and the addition caused counter to exceed u64::MAX - 1.
+    let flags = libc::EFD_CLOEXEC;
+    let fd = unsafe { libc::eventfd(0, flags) };
+    // Write u64 - 1, so the all subsequent write will block.
+    let sized_8_data: [u8; 8] = (u64::MAX - 1).to_ne_bytes();
+    let res: i64 = unsafe {
+        libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+    };
+    assert_eq!(res, 8);
+
+    let thread1 = thread::spawn(move || {
+        thread::park();
+        let sized_8_data = 1_u64.to_ne_bytes();
+        let res: i64 = unsafe {
+            libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+        };
+        // Make sure that write is successful.
+        assert_eq!(res, 8);
+    });
+
+    let thread2 = thread::spawn(move || {
+        thread::park();
+        let sized_8_data = 1_u64.to_ne_bytes();
+        let res: i64 = unsafe {
+            libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
+        };
+        // Make sure that write is successful.
+        assert_eq!(res, 8);
+    });
+
+    let thread3 = thread::spawn(move || {
+        thread::park();
+        let mut buf: [u8; 8] = [0; 8];
+        // This will unblock previously blocked eventfd read.
+        let res = read_bytes(fd, &mut buf);
+        // read returns number of bytes has been read, which is always 8.
+        assert_eq!(res, 8);
+        let counter = u64::from_ne_bytes(buf);
+        assert_eq!(counter, (u64::MAX - 1));
+    });
+
+    thread1.thread().unpark();
+    thread2.thread().unpark();
+    thread3.thread().unpark();
+
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+    thread3.join().unwrap();
+}
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 66843ca584b..4de315e3589 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -959,10 +959,20 @@ pub fn libm() {
         unsafe { ldexp(a, b) }
     }
 
-    assert_approx_eq!(64f32.sqrt(), 8f32);
-    assert_approx_eq!(64f64.sqrt(), 8f64);
+    assert_eq!(64_f32.sqrt(), 8_f32);
+    assert_eq!(64_f64.sqrt(), 8_f64);
+    assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY);
+    assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY);
+    assert_eq!(0.0_f32.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal);
+    assert_eq!(0.0_f64.sqrt().total_cmp(&0.0), std::cmp::Ordering::Equal);
+    assert_eq!((-0.0_f32).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal);
+    assert_eq!((-0.0_f64).sqrt().total_cmp(&-0.0), std::cmp::Ordering::Equal);
     assert!((-5.0_f32).sqrt().is_nan());
     assert!((-5.0_f64).sqrt().is_nan());
+    assert!(f32::NEG_INFINITY.sqrt().is_nan());
+    assert!(f64::NEG_INFINITY.sqrt().is_nan());
+    assert!(f32::NAN.sqrt().is_nan());
+    assert!(f64::NAN.sqrt().is_nan());
 
     assert_approx_eq!(25f32.powi(-2), 0.0016f32);
     assert_approx_eq!(23.2f64.powi(2), 538.24f64);
diff --git a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs b/src/tools/miri/tests/pass/stacked-borrows/2phase.rs
index eb543d691e1..fb4ba605837 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/2phase.rs
@@ -1,3 +1,6 @@
+// FIXME: this miscompiles with optimizations, see <https://github.com/rust-lang/rust/issues/132898>.
+//@compile-flags: -Zmir-opt-level=0
+
 trait S: Sized {
     fn tpb(&mut self, _s: Self) {}
 }
@@ -75,6 +78,25 @@ fn with_interior_mutability() {
     });
 }
 
+// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it.
+// Tree Borrows rejects it.
+fn aliasing_violation() {
+    struct Foo(u64);
+    impl Foo {
+        fn add(&mut self, n: u64) -> u64 {
+            self.0 + n
+        }
+    }
+
+    let mut f = Foo(0);
+    let alias = &mut f.0 as *mut u64;
+    let res = f.add(unsafe {
+        *alias = 42;
+        0
+    });
+    assert_eq!(res, 42);
+}
+
 fn main() {
     two_phase1();
     two_phase2();
@@ -84,4 +106,5 @@ fn main() {
     with_interior_mutability();
     two_phase_overlapping1();
     two_phase_overlapping2();
+    aliasing_violation();
 }
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
index c75824d7f9b..4261f411eea 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
@@ -8,6 +8,7 @@ fn main() {
     mut_raw_then_mut_shr();
     mut_shr_then_mut_raw();
     mut_raw_mut();
+    mut_raw_mut2();
     partially_invalidate_mut();
     drop_after_sharing();
     // direct_mut_to_const_raw();
@@ -96,6 +97,18 @@ fn mut_raw_mut() {
     assert_eq!(x, 4);
 }
 
+// A variant of `mut_raw_mut` that does *not* get accepted by Tree Borrows.
+// It's kind of an accident that we accept it in Stacked Borrows...
+fn mut_raw_mut2() {
+    unsafe {
+        let mut root = 0;
+        let to = &mut root as *mut i32;
+        *to = 0;
+        let _val = root;
+        *to = 0;
+    }
+}
+
 fn partially_invalidate_mut() {
     let data = &mut (0u8, 0u8);
     let reborrow = &mut *data as *mut (u8, u8);
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index 5a35e115d8f..4083d9398f6 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -620,7 +620,7 @@ fn delim_token_to_str(
                 ("{ ", " }")
             }
         }
-        Delimiter::Invisible => unreachable!(),
+        Delimiter::Invisible(_) => unreachable!(),
     };
     if use_multiple_lines {
         let indent_str = shape.indent.to_string_with_newline(context.config);
diff --git a/src/version b/src/version
index bd0f9e6c28f..f288d11142d 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.84.0
+1.85.0
diff --git a/tests/assembly/s390x-vector-abi.rs b/tests/assembly/s390x-vector-abi.rs
new file mode 100644
index 00000000000..c1935582561
--- /dev/null
+++ b/tests/assembly/s390x-vector-abi.rs
@@ -0,0 +1,322 @@
+//@ revisions: z10 z10_vector z13 z13_no_vector
+// ignore-tidy-linelength
+//@ assembly-output: emit-asm
+//@ compile-flags: -O -Z merge-functions=disabled
+//@[z10] compile-flags: --target s390x-unknown-linux-gnu --cfg no_vector
+//@[z10] needs-llvm-components: systemz
+//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
+//@[z10_vector] needs-llvm-components: systemz
+//@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13
+//@[z13] needs-llvm-components: systemz
+//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector --cfg no_vector
+//@[z13_no_vector] needs-llvm-components: systemz
+
+#![feature(no_core, lang_items, repr_simd, s390x_target_feature)]
+#![no_core]
+#![crate_type = "lib"]
+#![allow(non_camel_case_types)]
+
+// Cases where vector feature is disabled are rejected.
+// See tests/ui/simd-abi-checks-s390x.rs for test for them.
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "freeze"]
+pub trait Freeze {}
+
+impl<T: Copy, const N: usize> Copy for [T; N] {}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+impl<T: ?Sized> Copy for PhantomData<T> {}
+
+#[repr(simd)]
+pub struct i8x8([i8; 8]);
+#[repr(simd)]
+pub struct i8x16([i8; 16]);
+#[repr(simd)]
+pub struct i8x32([i8; 32]);
+#[repr(C)]
+pub struct Wrapper<T>(T);
+#[repr(C, align(16))]
+pub struct WrapperAlign16<T>(T);
+#[repr(C)]
+pub struct WrapperWithZst<T>(T, PhantomData<()>);
+#[repr(transparent)]
+pub struct TransparentWrapper<T>(T);
+
+impl Copy for i8 {}
+impl Copy for i64 {}
+impl Copy for i8x8 {}
+impl Copy for i8x16 {}
+impl Copy for i8x32 {}
+impl<T: Copy> Copy for Wrapper<T> {}
+impl<T: Copy> Copy for WrapperAlign16<T> {}
+impl<T: Copy> Copy for WrapperWithZst<T> {}
+impl<T: Copy> Copy for TransparentWrapper<T> {}
+
+// CHECK-LABEL: vector_ret_small:
+// CHECK: vlrepg %v24, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+    *x
+}
+// CHECK-LABEL: vector_ret:
+// CHECK: vl %v24, 0(%r2), 3
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+    *x
+}
+// CHECK-LABEL: vector_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 0(%r3), 4
+// z13-NEXT: vl %v1, 16(%r3), 4
+// z13-NEXT: vst %v1, 16(%r2), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 {
+    *x
+}
+
+// CHECK-LABEL: vector_wrapper_ret_small:
+// CHECK: mvc 0(8,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_ret_small(x: &Wrapper<i8x8>) -> Wrapper<i8x8> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_ret:
+// CHECK: mvc 0(16,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_ret(x: &Wrapper<i8x16>) -> Wrapper<i8x16> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 16(%r3), 4
+// z13-NEXT: vst %v0, 16(%r2), 4
+// z13-NEXT: vl %v0, 0(%r3), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_ret_large(x: &Wrapper<i8x32>) -> Wrapper<i8x32> {
+    *x
+}
+
+// CHECK-LABEL: vector_wrapper_padding_ret:
+// CHECK: mvc 0(16,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_padding_ret(x: &WrapperAlign16<i8x8>) -> WrapperAlign16<i8x8> {
+    *x
+}
+
+// CHECK-LABEL: vector_wrapper_with_zst_ret_small:
+// CHECK: mvc 0(8,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_ret_small(
+    x: &WrapperWithZst<i8x8>,
+) -> WrapperWithZst<i8x8> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_with_zst_ret:
+// CHECK: mvc 0(16,%r2), 0(%r3)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_ret(
+    x: &WrapperWithZst<i8x16>,
+) -> WrapperWithZst<i8x16> {
+    *x
+}
+// CHECK-LABEL: vector_wrapper_with_zst_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 16(%r3), 4
+// z13-NEXT: vst %v0, 16(%r2), 4
+// z13-NEXT: vl %v0, 0(%r3), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_ret_large(
+    x: &WrapperWithZst<i8x32>,
+) -> WrapperWithZst<i8x32> {
+    *x
+}
+
+// CHECK-LABEL: vector_transparent_wrapper_ret_small:
+// CHECK: vlrepg %v24, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_ret_small(
+    x: &TransparentWrapper<i8x8>,
+) -> TransparentWrapper<i8x8> {
+    *x
+}
+// CHECK-LABEL: vector_transparent_wrapper_ret:
+// CHECK: vl %v24, 0(%r2), 3
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_ret(
+    x: &TransparentWrapper<i8x16>,
+) -> TransparentWrapper<i8x16> {
+    *x
+}
+// CHECK-LABEL: vector_transparent_wrapper_ret_large:
+// z10: vl %v0, 16(%r3), 4
+// z10-NEXT: vl %v1, 0(%r3), 4
+// z10-NEXT: vst %v0, 16(%r2), 4
+// z10-NEXT: vst %v1, 0(%r2), 4
+// z10-NEXT: br %r14
+// z13: vl %v0, 0(%r3), 4
+// z13-NEXT: vl %v1, 16(%r3), 4
+// z13-NEXT: vst %v1, 16(%r2), 4
+// z13-NEXT: vst %v0, 0(%r2), 4
+// z13-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_ret_large(
+    x: &TransparentWrapper<i8x32>,
+) -> TransparentWrapper<i8x32> {
+    *x
+}
+
+// CHECK-LABEL: vector_arg_small:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+    unsafe { *(&x as *const i8x8 as *const i64) }
+}
+// CHECK-LABEL: vector_arg:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_arg(x: i8x16) -> i64 {
+    unsafe { *(&x as *const i8x16 as *const i64) }
+}
+// CHECK-LABEL: vector_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_arg_large(x: i8x32) -> i64 {
+    unsafe { *(&x as *const i8x32 as *const i64) }
+}
+
+// CHECK-LABEL: vector_wrapper_arg_small:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+    unsafe { *(&x as *const Wrapper<i8x8> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_arg:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+    unsafe { *(&x as *const Wrapper<i8x16> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 {
+    unsafe { *(&x as *const Wrapper<i8x32> as *const i64) }
+}
+
+// https://github.com/rust-lang/rust/pull/131586#discussion_r1837071121
+// CHECK-LABEL: vector_wrapper_padding_arg:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_padding_arg(x: WrapperAlign16<i8x8>) -> i64 {
+    unsafe { *(&x as *const WrapperAlign16<i8x8> as *const i64) }
+}
+
+// CHECK-LABEL: vector_wrapper_with_zst_arg_small:
+// CHECK: .cfi_startproc
+// CHECK-NOT: vlgvg
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_arg_small(x: WrapperWithZst<i8x8>) -> i64 {
+    unsafe { *(&x as *const WrapperWithZst<i8x8> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_with_zst_arg:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_arg(x: WrapperWithZst<i8x16>) -> i64 {
+    unsafe { *(&x as *const WrapperWithZst<i8x16> as *const i64) }
+}
+// CHECK-LABEL: vector_wrapper_with_zst_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_wrapper_with_zst_arg_large(x: WrapperWithZst<i8x32>) -> i64 {
+    unsafe { *(&x as *const WrapperWithZst<i8x32> as *const i64) }
+}
+
+// CHECK-LABEL: vector_transparent_wrapper_arg_small:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+    unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) }
+}
+// CHECK-LABEL: vector_transparent_wrapper_arg:
+// CHECK: vlgvg %r2, %v24, 0
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+    unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) }
+}
+// CHECK-LABEL: vector_transparent_wrapper_arg_large:
+// CHECK: lg %r2, 0(%r2)
+// CHECK-NEXT: br %r14
+#[cfg_attr(no_vector, target_feature(enable = "vector"))]
+#[no_mangle]
+unsafe extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 {
+    unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) }
+}
diff --git a/tests/codegen/aarch64-softfloat.rs b/tests/codegen/aarch64-softfloat.rs
new file mode 100644
index 00000000000..14d0054f80c
--- /dev/null
+++ b/tests/codegen/aarch64-softfloat.rs
@@ -0,0 +1,48 @@
+//@ compile-flags: --target aarch64-unknown-none-softfloat -Zmerge-functions=disabled
+//@ needs-llvm-components: aarch64
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+
+// CHECK: i64 @pass_f64_C(i64 {{[^,]*}})
+#[no_mangle]
+extern "C" fn pass_f64_C(x: f64) -> f64 {
+    x
+}
+
+// CHECK: i64 @pass_f32_pair_C(i64 {{[^,]*}})
+#[no_mangle]
+extern "C" fn pass_f32_pair_C(x: (f32, f32)) -> (f32, f32) {
+    x
+}
+
+// CHECK: [2 x i64] @pass_f64_pair_C([2 x i64] {{[^,]*}})
+#[no_mangle]
+extern "C" fn pass_f64_pair_C(x: (f64, f64)) -> (f64, f64) {
+    x
+}
+
+// CHECK: i64 @pass_f64_Rust(i64 {{[^,]*}})
+#[no_mangle]
+fn pass_f64_Rust(x: f64) -> f64 {
+    x
+}
+
+// CHECK: i64 @pass_f32_pair_Rust(i64 {{[^,]*}})
+#[no_mangle]
+fn pass_f32_pair_Rust(x: (f32, f32)) -> (f32, f32) {
+    x
+}
+
+// CHECK: void @pass_f64_pair_Rust(ptr {{[^,]*}}, ptr {{[^,]*}})
+#[no_mangle]
+fn pass_f64_pair_Rust(x: (f64, f64)) -> (f64, f64) {
+    x
+}
diff --git a/tests/crashes/113280.rs b/tests/crashes/113280.rs
deleted file mode 100644
index 86677f416fe..00000000000
--- a/tests/crashes/113280.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: #113280
-//@ only-x86_64
-
-#![feature(dyn_star, pointer_like_trait)]
-#![allow(incomplete_features)]
-
-use std::fmt::Debug;
-use std::marker::PointerLike;
-
-fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a {
-    f32::from_bits(0x1) as f64
-}
-
-fn main() {
-    println!("{:?}", make_dyn_star(Box::new(1i32)));
-}
diff --git a/tests/crashes/124350.rs b/tests/crashes/124350.rs
deleted file mode 100644
index d6038f280cf..00000000000
--- a/tests/crashes/124350.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ known-bug: #124350
-
-struct Node<const D: usize> {}
-
-impl Node<D>
-where
-    SmallVec<{ D * 2 }>:,
-{
-    fn new() -> Self {
-        let mut node = Node::new();
-        (&a, 0)();
-
-        node
-    }
-}
-
-struct SmallVec<T1, T2> {}
diff --git a/tests/crashes/124751.rs b/tests/crashes/124751.rs
index f15e39965d3..1372b97233d 100644
--- a/tests/crashes/124751.rs
+++ b/tests/crashes/124751.rs
@@ -1,5 +1,5 @@
 //@ known-bug: rust-lang/rust#124751
-//@ compile-flags: -Zunstable-options --edition=2024
+//@ edition: 2024
 
 #![feature(gen_blocks)]
 
diff --git a/tests/crashes/125758.rs b/tests/crashes/125758.rs
deleted file mode 100644
index 86c3b80abab..00000000000
--- a/tests/crashes/125758.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//@ known-bug: rust-lang/rust#125758
-#![feature(impl_trait_in_assoc_type)]
-
-trait Trait: Sized {
-    type Assoc2;
-}
-
-impl Trait for Bar {
-    type Assoc2 = impl std::fmt::Debug;
-}
-
-struct Foo {
-    field: <Bar as Trait>::Assoc2,
-}
-
-enum Bar {
-    C = 42,
-    D = 99,
-}
-
-static BAR: u8 = 42;
-
-static FOO2: (&Foo, &<Bar as Trait>::Assoc2) =
-    unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) };
-
-fn main() {}
diff --git a/tests/crashes/127351.rs b/tests/crashes/127351.rs
deleted file mode 100644
index e3f41594885..00000000000
--- a/tests/crashes/127351.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ known-bug: #127351
-#![feature(lazy_type_alias)]
-#![allow(incomplete_features)]
-
-struct Outer0<'a, T>(ExplicitTypeOutlives<'a, T>);
-type ExplicitTypeOutlives<'a, T: 'a> = (&'a (), T);
-
-pub struct Warns {
-    _significant_drop: ExplicitTypeOutlives,
-    field: String,
-}
-
-pub fn test(w: Warns) {
-    _ = || drop(w.field);
-}
-
-fn main() {}
diff --git a/tests/crashes/127353.rs b/tests/crashes/127353.rs
deleted file mode 100644
index 9bcb90b5c57..00000000000
--- a/tests/crashes/127353.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//@ known-bug: #127353
-#![feature(type_alias_impl_trait)]
-trait Trait<T> {}
-type Alias<'a, U> = impl Trait<U>;
-
-fn f<'a>() -> Alias<'a, ()> {}
-
-pub enum UninhabitedVariants {
-    Tuple(Alias),
-}
-
-struct A;
-
-fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
-    match x {}
-}
-
-fn main() {}
diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs
deleted file mode 100644
index 81149c2ef84..00000000000
--- a/tests/crashes/127676.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #127676
-//@ edition:2018
-
-#![feature(dyn_star,const_async_blocks)]
-
-static S: dyn* Send + Sync = async { 42 };
-
-pub fn main() {}
diff --git a/tests/crashes/127742.rs b/tests/crashes/127742.rs
deleted file mode 100644
index 24add454135..00000000000
--- a/tests/crashes/127742.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//@ known-bug: #127742
-struct Vtable(dyn Cap);  // missing lifetime
-
-trait Cap<'a> {}
-
-union Transmute {
-    t: u64,  // ICEs with u64, u128, or usize. Correctly errors with u32.
-    u: &'static Vtable,
-}
-
-const G: &'static Vtable = unsafe { Transmute { t: 1 }.u };
diff --git a/tests/crashes/130521.rs b/tests/crashes/130521.rs
index 7c078ab5790..ccc2b444b82 100644
--- a/tests/crashes/130521.rs
+++ b/tests/crashes/130521.rs
@@ -6,7 +6,7 @@ struct Vtable(dyn Cap);
 trait Cap<'a> {}
 
 union Transmute {
-    t: u64,
+    t: u128,
     u: &'static Vtable,
 }
 
diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout
index dbd67b57df2..8f6fde69c29 100644
--- a/tests/run-make/rustc-help/help-v.stdout
+++ b/tests/run-make/rustc-help/help-v.stdout
@@ -25,7 +25,7 @@ Options:
         --edition 2015|2018|2021|2024
                         Specify which edition of the compiler to use when
                         compiling code. The default is 2015 and the latest
-                        stable edition is 2021.
+                        stable edition is 2024.
         --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
                         Comma separated list of types of output for the
                         compiler to emit
diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout
index a7d07162799..131efa93282 100644
--- a/tests/run-make/rustc-help/help.stdout
+++ b/tests/run-make/rustc-help/help.stdout
@@ -25,7 +25,7 @@ Options:
         --edition 2015|2018|2021|2024
                         Specify which edition of the compiler to use when
                         compiling code. The default is 2015 and the latest
-                        stable edition is 2021.
+                        stable edition is 2024.
         --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
                         Comma separated list of types of output for the
                         compiler to emit
diff --git a/tests/run-make/unstable-feature-usage-metrics/lib.rs b/tests/run-make/unstable-feature-usage-metrics/lib.rs
new file mode 100644
index 00000000000..2202d722c49
--- /dev/null
+++ b/tests/run-make/unstable-feature-usage-metrics/lib.rs
@@ -0,0 +1,9 @@
+#![feature(ascii_char)] // random lib feature
+#![feature(box_patterns)] // random lang feature
+
+// picked arbitrary unstable features, just need a random lib and lang feature, ideally ones that
+// won't be stabilized any time soon so we don't have to update this test
+
+fn main() {
+    println!("foobar");
+}
diff --git a/tests/run-make/unstable-feature-usage-metrics/rmake.rs b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
new file mode 100644
index 00000000000..1397548a6fc
--- /dev/null
+++ b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
@@ -0,0 +1,87 @@
+//! This test checks if unstable feature usage metric dump files `unstable-feature-usage*.json` work
+//! as expected.
+//!
+//! - Basic sanity checks on a default ICE dump.
+//!
+//! See <https://github.com/rust-lang/rust/issues/129485>.
+//!
+//! # Test history
+//!
+//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming
+//! those will be present in this test as well on the same platform
+
+//@ ignore-windows
+//FIXME(#128911): still flakey on i686-mingw.
+
+use std::path::{Path, PathBuf};
+
+use run_make_support::rfs::create_dir_all;
+use run_make_support::{
+    cwd, filename_contains, has_extension, rfs, run_in_tmpdir, rustc, serde_json,
+    shallow_find_files,
+};
+
+fn find_feature_usage_metrics<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
+    shallow_find_files(dir, |path| {
+        if filename_contains(path, "unstable_feature_usage") && has_extension(path, "json") {
+            true
+        } else {
+            dbg!(path);
+            false
+        }
+    })
+}
+
+fn main() {
+    test_metrics_dump();
+    test_metrics_errors();
+}
+
+#[track_caller]
+fn test_metrics_dump() {
+    run_in_tmpdir(|| {
+        let metrics_dir = cwd().join("metrics");
+        create_dir_all(&metrics_dir);
+        rustc()
+            .input("lib.rs")
+            .env("RUST_BACKTRACE", "short")
+            .arg(format!("-Zmetrics-dir={}", metrics_dir.display()))
+            .run();
+        let mut metrics = find_feature_usage_metrics(&metrics_dir);
+        let json_path =
+            metrics.pop().expect("there should be one metrics file in the output directory");
+
+        // After the `pop` above, there should be no files left.
+        assert!(
+            metrics.is_empty(),
+            "there should be no more than one metrics file in the output directory"
+        );
+
+        let message = rfs::read_to_string(json_path);
+        let parsed: serde_json::Value =
+            serde_json::from_str(&message).expect("metrics should be dumped as json");
+        let expected = serde_json::json!(
+            {
+                "lib_features":[{"symbol":"ascii_char"}],
+                "lang_features":[{"symbol":"box_patterns","since":null}]
+            }
+        );
+
+        assert_eq!(expected, parsed);
+    });
+}
+
+#[track_caller]
+fn test_metrics_errors() {
+    run_in_tmpdir(|| {
+        rustc()
+            .input("lib.rs")
+            .env("RUST_BACKTRACE", "short")
+            .arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist")
+            .run_fail()
+            .assert_stderr_contains(
+                "error: cannot dump feature usage metrics: No such file or directory",
+            )
+            .assert_stdout_not_contains("internal compiler error");
+    });
+}
diff --git a/tests/rustdoc-ui/2024-doctests-checks.rs b/tests/rustdoc-ui/2024-doctests-checks.rs
index 464cf5b200d..f3e4e10f571 100644
--- a/tests/rustdoc-ui/2024-doctests-checks.rs
+++ b/tests/rustdoc-ui/2024-doctests-checks.rs
@@ -1,5 +1,6 @@
 //@ check-pass
-//@ compile-flags: --test --test-args=--test-threads=1 -Zunstable-options --edition 2024
+//@ edition: 2024
+//@ compile-flags: --test --test-args=--test-threads=1
 //@ normalize-stdout-test: "tests/rustdoc-ui" -> "$$DIR"
 //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ normalize-stdout-test: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
diff --git a/tests/rustdoc-ui/2024-doctests-checks.stdout b/tests/rustdoc-ui/2024-doctests-checks.stdout
index d1064084a85..534fe466fe7 100644
--- a/tests/rustdoc-ui/2024-doctests-checks.stdout
+++ b/tests/rustdoc-ui/2024-doctests-checks.stdout
@@ -1,12 +1,12 @@
 
 running 1 test
-test $DIR/2024-doctests-checks.rs - Foo (line 7) ... ok
+test $DIR/2024-doctests-checks.rs - Foo (line 8) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
 
 running 1 test
-test $DIR/2024-doctests-checks.rs - Foo (line 14) ... ok
+test $DIR/2024-doctests-checks.rs - Foo (line 15) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/2024-doctests-crate-attribute.rs b/tests/rustdoc-ui/2024-doctests-crate-attribute.rs
index 4984fdfe194..a353fc7cc44 100644
--- a/tests/rustdoc-ui/2024-doctests-crate-attribute.rs
+++ b/tests/rustdoc-ui/2024-doctests-crate-attribute.rs
@@ -1,5 +1,6 @@
 //@ check-pass
-//@ compile-flags: --test --test-args=--test-threads=1 -Zunstable-options --edition 2024
+//@ edition: 2024
+//@ compile-flags: --test --test-args=--test-threads=1
 //@ normalize-stdout-test: "tests/rustdoc-ui" -> "$$DIR"
 //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ normalize-stdout-test: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
diff --git a/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout b/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout
index 29702ce8929..c084ac4522e 100644
--- a/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout
+++ b/tests/rustdoc-ui/2024-doctests-crate-attribute.stdout
@@ -1,12 +1,12 @@
 
 running 1 test
-test $DIR/2024-doctests-crate-attribute.rs - Foo (line 19) ... ok
+test $DIR/2024-doctests-crate-attribute.rs - Foo (line 20) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
 
 running 1 test
-test $DIR/2024-doctests-crate-attribute.rs - Foo (line 10) ... ok
+test $DIR/2024-doctests-crate-attribute.rs - Foo (line 11) ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs b/tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs
index 354427000bf..388b8f310ae 100644
--- a/tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs
+++ b/tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs
@@ -1,5 +1,4 @@
 //@ edition:2024
-//@ compile-flags:-Z unstable-options
 #![crate_name="extern_macros"]
 #[macro_export]
 macro_rules! attrs_on_struct {
diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.rs b/tests/rustdoc-ui/doctest/dead-code-2024.rs
index 4c77112e61a..41459c5e651 100644
--- a/tests/rustdoc-ui/doctest/dead-code-2024.rs
+++ b/tests/rustdoc-ui/doctest/dead-code-2024.rs
@@ -1,6 +1,7 @@
 // This test ensures that the 2024 edition merged doctest will not use `#[allow(unused)]`.
 
-//@ compile-flags:--test -Zunstable-options --edition 2024
+//@ edition: 2024
+//@ compile-flags:--test
 //@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ failure-status: 101
diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.stdout b/tests/rustdoc-ui/doctest/dead-code-2024.stdout
index 69dd4e2ede1..a943a177e10 100644
--- a/tests/rustdoc-ui/doctest/dead-code-2024.stdout
+++ b/tests/rustdoc-ui/doctest/dead-code-2024.stdout
@@ -1,18 +1,18 @@
 
 running 1 test
-test $DIR/dead-code-2024.rs - f (line 12) - compile ... FAILED
+test $DIR/dead-code-2024.rs - f (line 13) - compile ... FAILED
 
 failures:
 
----- $DIR/dead-code-2024.rs - f (line 12) stdout ----
+---- $DIR/dead-code-2024.rs - f (line 13) stdout ----
 error: trait `T` is never used
-  --> $DIR/dead-code-2024.rs:13:7
+  --> $DIR/dead-code-2024.rs:14:7
    |
 LL | trait T { fn f(); }
    |       ^
    |
 note: the lint level is defined here
-  --> $DIR/dead-code-2024.rs:11:9
+  --> $DIR/dead-code-2024.rs:12:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
@@ -23,7 +23,7 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/dead-code-2024.rs - f (line 12)
+    $DIR/dead-code-2024.rs - f (line 13)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs
index 4018e37105f..d057218688c 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs
+++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs
@@ -1,7 +1,8 @@
 // FIXME: if/when the output of the test harness can be tested on its own, this test should be
 // adapted to use that, and that normalize line can go away
 
-//@ compile-flags:--test -Z unstable-options --edition 2024
+//@ edition: 2024
+//@ compile-flags:--test
 //@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ failure-status: 101
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
index cb3456e087e..90c0463d832 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
@@ -1,14 +1,14 @@
 
 running 1 test
-test $DIR/failed-doctest-should-panic.rs - Foo (line 9) - should panic ... FAILED
+test $DIR/failed-doctest-should-panic.rs - Foo (line 10) - should panic ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-should-panic.rs - Foo (line 9) stdout ----
+---- $DIR/failed-doctest-should-panic.rs - Foo (line 10) stdout ----
 note: test did not panic as expected
 
 failures:
-    $DIR/failed-doctest-should-panic.rs - Foo (line 9)
+    $DIR/failed-doctest-should-panic.rs - Foo (line 10)
 
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs b/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs
index 4c21d542951..754791361e8 100644
--- a/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs
+++ b/tests/rustdoc-ui/doctest/merged-ignore-no_run.rs
@@ -1,4 +1,5 @@
-//@ compile-flags:--test --test-args=--test-threads=1 -Zunstable-options --edition 2024
+//@ edition: 2024
+//@ compile-flags:--test --test-args=--test-threads=1
 //@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
 //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
 //@ check-pass
diff --git a/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout b/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout
index f2cb1e7e72f..a32da0aeb96 100644
--- a/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout
+++ b/tests/rustdoc-ui/doctest/merged-ignore-no_run.stdout
@@ -1,7 +1,7 @@
 
 running 2 tests
-test $DIR/merged-ignore-no_run.rs - ignored (line 6) ... ignored
-test $DIR/merged-ignore-no_run.rs - no_run (line 11) - compile ... ok
+test $DIR/merged-ignore-no_run.rs - ignored (line 7) ... ignored
+test $DIR/merged-ignore-no_run.rs - no_run (line 12) - compile ... ok
 
 test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.rs b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs
index aac43031546..35d1c738bb1 100644
--- a/tests/rustdoc-ui/doctest/standalone-warning-2024.rs
+++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs
@@ -1,6 +1,7 @@
 // This test checks that it will output warnings for usage of `standalone` or `standalone_crate`.
 
-//@ compile-flags:--test -Zunstable-options --edition 2024
+//@ edition: 2024
+//@ compile-flags:--test
 //@ 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"
diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
index d69d03d8657..bfc1e919404 100644
--- a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
+++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr
@@ -1,34 +1,34 @@
 error: unknown attribute `standalone`
-  --> $DIR/standalone-warning-2024.rs:10:1
+  --> $DIR/standalone-warning-2024.rs:11:1
    |
-10 | / //! ```standalone
-11 | | //! bla
-12 | | //! ```
-13 | | //!
-14 | | //! ```standalone-crate
-15 | | //! bla
-16 | | //! ```
+11 | / //! ```standalone
+12 | | //! bla
+13 | | //! ```
+14 | | //!
+15 | | //! ```standalone-crate
+16 | | //! bla
+17 | | //! ```
    | |_______^
    |
    = 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
+  --> $DIR/standalone-warning-2024.rs:9:9
    |
-8  | #![deny(warnings)]
+9  | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
 
 error: unknown attribute `standalone-crate`
-  --> $DIR/standalone-warning-2024.rs:10:1
+  --> $DIR/standalone-warning-2024.rs:11:1
    |
-10 | / //! ```standalone
-11 | | //! bla
-12 | | //! ```
-13 | | //!
-14 | | //! ```standalone-crate
-15 | | //! bla
-16 | | //! ```
+11 | / //! ```standalone
+12 | | //! bla
+13 | | //! ```
+14 | | //!
+15 | | //! ```standalone-crate
+16 | | //! bla
+17 | | //! ```
    | |_______^
    |
    = help: use `standalone_crate` to compile this code block separately
diff --git a/tests/rustdoc-ui/doctest/wrong-ast-2024.rs b/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
index 7b4fa8fd2c9..a1455c01bc6 100644
--- a/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
+++ b/tests/rustdoc-ui/doctest/wrong-ast-2024.rs
@@ -1,4 +1,5 @@
-//@ compile-flags:--test --test-args=--test-threads=1 -Zunstable-options --edition 2024
+//@ edition: 2024
+//@ compile-flags:--test --test-args=--test-threads=1
 //@ 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"
diff --git a/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
index 22c8ce468fd..62e1fb10b9f 100644
--- a/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
+++ b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout
@@ -1,17 +1,17 @@
 
 running 1 test
-test $DIR/wrong-ast-2024.rs - three (line 17) - should panic ... ok
+test $DIR/wrong-ast-2024.rs - three (line 18) - should panic ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
 
 running 2 tests
-test $DIR/wrong-ast-2024.rs - one (line 7) ... FAILED
-test $DIR/wrong-ast-2024.rs - two (line 12) ... FAILED
+test $DIR/wrong-ast-2024.rs - one (line 8) ... FAILED
+test $DIR/wrong-ast-2024.rs - two (line 13) ... FAILED
 
 failures:
 
----- $DIR/wrong-ast-2024.rs - one (line 7) stdout ----
+---- $DIR/wrong-ast-2024.rs - one (line 8) stdout ----
 error[E0758]: unterminated block comment
   --> $DIR/wrong-ast-2024.rs:$LINE:$COL
    |
@@ -22,7 +22,7 @@ error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0758`.
 Couldn't compile the test.
----- $DIR/wrong-ast-2024.rs - two (line 12) stdout ----
+---- $DIR/wrong-ast-2024.rs - two (line 13) stdout ----
 error: unexpected closing delimiter: `}`
   --> $DIR/wrong-ast-2024.rs:$LINE:$COL
    |
@@ -34,8 +34,8 @@ error: aborting due to 1 previous error
 Couldn't compile the test.
 
 failures:
-    $DIR/wrong-ast-2024.rs - one (line 7)
-    $DIR/wrong-ast-2024.rs - two (line 12)
+    $DIR/wrong-ast-2024.rs - one (line 8)
+    $DIR/wrong-ast-2024.rs - two (line 13)
 
 test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/tests/ui/asm/x86_64/goto-block-safe.rs b/tests/ui/asm/x86_64/goto-block-safe.rs
new file mode 100644
index 00000000000..ee833a48a4b
--- /dev/null
+++ b/tests/ui/asm/x86_64/goto-block-safe.rs
@@ -0,0 +1,23 @@
+//@ only-x86_64
+//@ needs-asm-support
+
+#![deny(unreachable_code)]
+#![feature(asm_goto)]
+
+use std::arch::asm;
+
+fn goto_fallthough() {
+    unsafe {
+        asm!(
+            "/* {} */",
+            label {
+                core::hint::unreachable_unchecked();
+                //~^ ERROR [E0133]
+            }
+        )
+    }
+}
+
+fn main() {
+    goto_fallthough();
+}
diff --git a/tests/ui/asm/x86_64/goto-block-safe.stderr b/tests/ui/asm/x86_64/goto-block-safe.stderr
new file mode 100644
index 00000000000..49818db7484
--- /dev/null
+++ b/tests/ui/asm/x86_64/goto-block-safe.stderr
@@ -0,0 +1,14 @@
+error[E0133]: call to unsafe function `unreachable_unchecked` is unsafe and requires unsafe function or block
+  --> $DIR/goto-block-safe.rs:14:17
+   |
+LL |     unsafe {
+   |     ------ items do not inherit unsafety from separate enclosing items
+...
+LL |                 core::hint::unreachable_unchecked();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr
index 396167f4070..e965c40fb5b 100644
--- a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr
+++ b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}: AsyncFn<()>` is not satisfied
+error[E0277]: the trait bound `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}: AsyncFn()` is not satisfied
   --> $DIR/fn-exception-target-features.rs:16:10
    |
 LL |     test(target_feature);
-   |     ---- ^^^^^^^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}`
+   |     ---- ^^^^^^^^^^^^^^ the trait `AsyncFn()` is not implemented for fn item `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/async-await/async-closures/fn-exception.stderr b/tests/ui/async-await/async-closures/fn-exception.stderr
index bacd079af0f..20132e42833 100644
--- a/tests/ui/async-await/async-closures/fn-exception.stderr
+++ b/tests/ui/async-await/async-closures/fn-exception.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}: AsyncFn<()>` is not satisfied
+error[E0277]: the trait bound `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}: AsyncFn()` is not satisfied
   --> $DIR/fn-exception.rs:19:10
    |
 LL |     test(unsafety);
-   |     ---- ^^^^^^^^ the trait `AsyncFn<()>` is not implemented for fn item `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}`
+   |     ---- ^^^^^^^^ the trait `AsyncFn()` is not implemented for fn item `unsafe fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {unsafety}`
    |     |
    |     required by a bound introduced by this call
    |
@@ -12,11 +12,11 @@ note: required by a bound in `test`
 LL | fn test(f: impl async Fn()) {}
    |                 ^^^^^^^^^^ required by this bound in `test`
 
-error[E0277]: the trait bound `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}: AsyncFn<()>` is not satisfied
+error[E0277]: the trait bound `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}: AsyncFn()` is not satisfied
   --> $DIR/fn-exception.rs:20:10
    |
 LL |     test(abi);
-   |     ---- ^^^ the trait `AsyncFn<()>` is not implemented for fn item `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}`
+   |     ---- ^^^ the trait `AsyncFn()` is not implemented for fn item `extern "C" fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {abi}`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs
new file mode 100644
index 00000000000..2e7cf1b09fd
--- /dev/null
+++ b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.rs
@@ -0,0 +1,14 @@
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+use std::ops::AsyncFnMut;
+
+fn produce() -> impl AsyncFnMut() -> &'static str {
+    async || ""
+}
+
+fn main() {
+    let x: i32 = produce();
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr
new file mode 100644
index 00000000000..863e61eb35a
--- /dev/null
+++ b/tests/ui/async-await/async-closures/pretty-async-fn-opaque.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/pretty-async-fn-opaque.rs:12:18
+   |
+LL | fn produce() -> impl AsyncFnMut() -> &'static str {
+   |                 --------------------------------- the found opaque type
+...
+LL |     let x: i32 = produce();
+   |            ---   ^^^^^^^^^ expected `i32`, found opaque type
+   |            |
+   |            expected due to this
+   |
+   = note:     expected type `i32`
+           found opaque type `impl AsyncFnMut() -> &'static str`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr
index 25101cb65df..9fbceafd75d 100644
--- a/tests/ui/async-await/async-fn/edition-2015.stderr
+++ b/tests/ui/async-await/async-fn/edition-2015.stderr
@@ -4,7 +4,7 @@ error: `async` trait bounds are only allowed in Rust 2018 or later
 LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
    |                ^^^^^
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: `async` trait bounds are only allowed in Rust 2018 or later
@@ -13,7 +13,7 @@ error: `async` trait bounds are only allowed in Rust 2018 or later
 LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
    |                                    ^^^^^
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0658]: async closures are unstable
diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.stderr
index c40cdc5acec..f39ec033e70 100644
--- a/tests/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/tests/ui/async-await/edition-deny-async-fns-2015.stderr
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn foo() {}
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -13,7 +13,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | fn baz() { async fn foo() {} }
    |            ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -22,7 +22,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn async_baz() {
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -31,7 +31,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn bar() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -40,7 +40,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -49,7 +49,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     async fn foo() {}
    |     ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -58,7 +58,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |         async fn bar() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -67,7 +67,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |         async fn foo() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
@@ -76,7 +76,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |             async fn bar() {}
    |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: aborting due to 9 previous errors
diff --git a/tests/ui/async-await/for-await-passthrough.rs b/tests/ui/async-await/for-await-passthrough.rs
index b4fba6b2f76..1918e2f61aa 100644
--- a/tests/ui/async-await/for-await-passthrough.rs
+++ b/tests/ui/async-await/for-await-passthrough.rs
@@ -1,6 +1,5 @@
 //@ run-pass
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 #![feature(async_iterator, async_iter_from_iter, async_for_loop, noop_waker,
            gen_blocks)]
 
diff --git a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs
index e1fae0f0e93..bcb5cb94b77 100644
--- a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs
+++ b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.rs
@@ -12,7 +12,7 @@ fn await_on_struct_missing() {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP set `edition = "2024"` in `Cargo.toml`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -26,7 +26,7 @@ fn await_on_struct_similar() {
     //~| NOTE unknown field
     //~| HELP a field with a similar name exists
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP set `edition = "2024"` in `Cargo.toml`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -35,7 +35,7 @@ fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP set `edition = "2024"` in `Cargo.toml`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -44,6 +44,6 @@ fn await_on_apit(x: impl Future<Output = ()>) {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP set `edition = "2021"` in `Cargo.toml`
+    //~| HELP set `edition = "2024"` in `Cargo.toml`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
diff --git a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr
index dd863ca541c..c8bbb3a243c 100644
--- a/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr
+++ b/tests/ui/async-await/suggest-switching-edition-on-await-cargo.stderr
@@ -5,7 +5,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: set `edition = "2024"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `await_on_struct_similar::S`
@@ -15,7 +15,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: set `edition = "2024"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 help: a field with a similar name exists
    |
@@ -29,7 +29,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: set `edition = "2024"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `impl Future<Output = ()>`
@@ -39,7 +39,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: set `edition = "2021"` in `Cargo.toml`
+   = help: set `edition = "2024"` in `Cargo.toml`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/async-await/suggest-switching-edition-on-await.rs b/tests/ui/async-await/suggest-switching-edition-on-await.rs
index 10e245796ee..0907a87e02c 100644
--- a/tests/ui/async-await/suggest-switching-edition-on-await.rs
+++ b/tests/ui/async-await/suggest-switching-edition-on-await.rs
@@ -10,7 +10,7 @@ fn await_on_struct_missing() {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -24,7 +24,7 @@ fn await_on_struct_similar() {
     //~| NOTE unknown field
     //~| HELP a field with a similar name exists
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -33,7 +33,7 @@ fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -42,6 +42,6 @@ fn await_on_apit(x: impl Future<Output = ()>) {
     //~^ ERROR no field `await` on type
     //~| NOTE unknown field
     //~| NOTE to `.await` a `Future`, switch to Rust 2018
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
diff --git a/tests/ui/async-await/suggest-switching-edition-on-await.stderr b/tests/ui/async-await/suggest-switching-edition-on-await.stderr
index 0ed256b059f..ef5a5f81269 100644
--- a/tests/ui/async-await/suggest-switching-edition-on-await.stderr
+++ b/tests/ui/async-await/suggest-switching-edition-on-await.stderr
@@ -5,7 +5,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `await_on_struct_similar::S`
@@ -15,7 +15,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 help: a field with a similar name exists
    |
@@ -29,7 +29,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0609]: no field `await` on type `impl Future<Output = ()>`
@@ -39,7 +39,7 @@ LL |     x.await;
    |       ^^^^^ unknown field
    |
    = note: to `.await` a `Future`, switch to Rust 2018 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
index 273b127bf9c..19046c08ca8 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 
 #[unsafe(cfg(any()))] //~ ERROR: is not an unsafe attribute
 fn a() {}
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
index 445d239d867..b549a638d5e 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
@@ -1,5 +1,5 @@
 error: `cfg` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:4:3
+  --> $DIR/extraneous-unsafe-attributes.rs:3:3
    |
 LL | #[unsafe(cfg(any()))]
    |   ^^^^^^ this is not an unsafe attribute
@@ -7,7 +7,7 @@ LL | #[unsafe(cfg(any()))]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `cfg_attr` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:7:3
+  --> $DIR/extraneous-unsafe-attributes.rs:6:3
    |
 LL | #[unsafe(cfg_attr(any(), allow(dead_code)))]
    |   ^^^^^^ this is not an unsafe attribute
@@ -15,7 +15,7 @@ LL | #[unsafe(cfg_attr(any(), allow(dead_code)))]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `test` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:10:3
+  --> $DIR/extraneous-unsafe-attributes.rs:9:3
    |
 LL | #[unsafe(test)]
    |   ^^^^^^ this is not an unsafe attribute
@@ -23,7 +23,7 @@ LL | #[unsafe(test)]
    = note: extraneous unsafe is not allowed in attributes
 
 error: expected identifier, found keyword `unsafe`
-  --> $DIR/extraneous-unsafe-attributes.rs:31:19
+  --> $DIR/extraneous-unsafe-attributes.rs:30:19
    |
 LL |     let _a = cfg!(unsafe(foo));
    |                   ^^^^^^ expected identifier, found keyword
@@ -34,13 +34,13 @@ LL |     let _a = cfg!(r#unsafe(foo));
    |                   ++
 
 error[E0537]: invalid predicate `r#unsafe`
-  --> $DIR/extraneous-unsafe-attributes.rs:31:19
+  --> $DIR/extraneous-unsafe-attributes.rs:30:19
    |
 LL |     let _a = cfg!(unsafe(foo));
    |                   ^^^^^^^^^^^
 
 error: `ignore` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:13:3
+  --> $DIR/extraneous-unsafe-attributes.rs:12:3
    |
 LL | #[unsafe(ignore = "test")]
    |   ^^^^^^ this is not an unsafe attribute
@@ -48,7 +48,7 @@ LL | #[unsafe(ignore = "test")]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `should_panic` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:16:3
+  --> $DIR/extraneous-unsafe-attributes.rs:15:3
    |
 LL | #[unsafe(should_panic(expected = "test"))]
    |   ^^^^^^ this is not an unsafe attribute
@@ -56,7 +56,7 @@ LL | #[unsafe(should_panic(expected = "test"))]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `macro_use` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:19:3
+  --> $DIR/extraneous-unsafe-attributes.rs:18:3
    |
 LL | #[unsafe(macro_use)]
    |   ^^^^^^ this is not an unsafe attribute
@@ -64,7 +64,7 @@ LL | #[unsafe(macro_use)]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `macro_export` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:21:7
+  --> $DIR/extraneous-unsafe-attributes.rs:20:7
    |
 LL |     #[unsafe(macro_export)]
    |       ^^^^^^ this is not an unsafe attribute
@@ -72,7 +72,7 @@ LL |     #[unsafe(macro_export)]
    = note: extraneous unsafe is not allowed in attributes
 
 error: `used` is not an unsafe attribute
-  --> $DIR/extraneous-unsafe-attributes.rs:27:3
+  --> $DIR/extraneous-unsafe-attributes.rs:26:3
    |
 LL | #[unsafe(used)]
    |   ^^^^^^ this is not an unsafe attribute
diff --git a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
index ca8c2a16d32..5f980c46a1f 100644
--- a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
+++ b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
@@ -97,16 +97,19 @@ LL |         if let Refutable::A = v3 { todo!() };
 error[E0005]: refutable pattern in local binding
   --> $DIR/bad-pattern.rs:19:13
    |
+LL |     const PAT: u32 = 0;
+   |     -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
+...
 LL |         let PAT = v1;
-   |             ^^^
-   |             |
-   |             pattern `1_u32..=u32::MAX` not covered
-   |             missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
-   |             help: introduce a variable instead: `PAT_var`
+   |             ^^^ pattern `1_u32..=u32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u32`
+help: introduce a variable instead
+   |
+LL |         let PAT_var = v1;
+   |             ~~~~~~~
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/closures/correct-args-on-call-suggestion.rs b/tests/ui/closures/correct-args-on-call-suggestion.rs
new file mode 100644
index 00000000000..fa7915a7c03
--- /dev/null
+++ b/tests/ui/closures/correct-args-on-call-suggestion.rs
@@ -0,0 +1,7 @@
+// Ensure we give the right args when we suggest calling a closure.
+
+fn main() {
+    let x = |a: i32, b: i32| a + b;
+    let y: i32 = x;
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/closures/correct-args-on-call-suggestion.stderr b/tests/ui/closures/correct-args-on-call-suggestion.stderr
new file mode 100644
index 00000000000..2613c7776b2
--- /dev/null
+++ b/tests/ui/closures/correct-args-on-call-suggestion.stderr
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/correct-args-on-call-suggestion.rs:5:18
+   |
+LL |     let x = |a: i32, b: i32| a + b;
+   |             ---------------- the found closure
+LL |     let y: i32 = x;
+   |            ---   ^ expected `i32`, found closure
+   |            |
+   |            expected due to this
+   |
+   = note: expected type `i32`
+           found closure `{closure@$DIR/correct-args-on-call-suggestion.rs:4:13: 4:29}`
+help: use parentheses to call this closure
+   |
+LL |     let y: i32 = x(/* i32 */, /* i32 */);
+   |                   ++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.rs b/tests/ui/codemap_tests/huge_multispan_highlight.rs
index 7d7b7570823..6f6834b01bd 100644
--- a/tests/ui/codemap_tests/huge_multispan_highlight.rs
+++ b/tests/ui/codemap_tests/huge_multispan_highlight.rs
@@ -1,7 +1,7 @@
 //@ revisions: ascii unicode
 //@ compile-flags: --color=always
 //@[ascii] compile-flags: --error-format=human
-//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode
+//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode
 //@ ignore-windows
 fn main() {
     let _ = match true {
diff --git a/tests/ui/confuse-field-and-method/issue-18343.stderr b/tests/ui/confuse-field-and-method/issue-18343.stderr
index a51fd4f02aa..e50c971d837 100644
--- a/tests/ui/confuse-field-and-method/issue-18343.stderr
+++ b/tests/ui/confuse-field-and-method/issue-18343.stderr
@@ -7,7 +7,7 @@ LL | struct Obj<F> where F: FnMut() -> u32 {
 LL |     o.closure();
    |       ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the closure stored in `closure`, surround the field access with parentheses
    |
 LL |     (o.closure)();
    |     +         +
diff --git a/tests/ui/confuse-field-and-method/issue-2392.stderr b/tests/ui/confuse-field-and-method/issue-2392.stderr
index 440fbb27c00..77930de44a7 100644
--- a/tests/ui/confuse-field-and-method/issue-2392.stderr
+++ b/tests/ui/confuse-field-and-method/issue-2392.stderr
@@ -7,7 +7,7 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
 LL |     o_closure.closure();
    |               ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the closure stored in `closure`, surround the field access with parentheses
    |
 LL |     (o_closure.closure)();
    |     +                 +
@@ -46,7 +46,7 @@ LL | struct BoxedObj {
 LL |     boxed_fn.boxed_closure();
    |              ^^^^^^^^^^^^^ field, not a method
    |
-help: to call the function stored in `boxed_closure`, surround the field access with parentheses
+help: to call the trait object stored in `boxed_closure`, surround the field access with parentheses
    |
 LL |     (boxed_fn.boxed_closure)();
    |     +                      +
@@ -60,7 +60,7 @@ LL | struct BoxedObj {
 LL |     boxed_closure.boxed_closure();
    |                   ^^^^^^^^^^^^^ field, not a method
    |
-help: to call the function stored in `boxed_closure`, surround the field access with parentheses
+help: to call the trait object stored in `boxed_closure`, surround the field access with parentheses
    |
 LL |     (boxed_closure.boxed_closure)();
    |     +                           +
@@ -99,7 +99,7 @@ LL | struct Obj<F> where F: FnOnce() -> u32 {
 LL |     check_expression().closure();
    |                        ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the trait object stored in `closure`, surround the field access with parentheses
    |
 LL |     (check_expression().closure)();
    |     +                          +
@@ -113,7 +113,7 @@ LL | struct FuncContainer {
 LL |             (*self.container).f1(1);
    |                               ^^ field, not a method
    |
-help: to call the function stored in `f1`, surround the field access with parentheses
+help: to call the function pointer stored in `f1`, surround the field access with parentheses
    |
 LL |             ((*self.container).f1)(1);
    |             +                    +
@@ -127,7 +127,7 @@ LL | struct FuncContainer {
 LL |             (*self.container).f2(1);
    |                               ^^ field, not a method
    |
-help: to call the function stored in `f2`, surround the field access with parentheses
+help: to call the function pointer stored in `f2`, surround the field access with parentheses
    |
 LL |             ((*self.container).f2)(1);
    |             +                    +
@@ -141,7 +141,7 @@ LL | struct FuncContainer {
 LL |             (*self.container).f3(1);
    |                               ^^ field, not a method
    |
-help: to call the function stored in `f3`, surround the field access with parentheses
+help: to call the function pointer stored in `f3`, surround the field access with parentheses
    |
 LL |             ((*self.container).f3)(1);
    |             +                    +
diff --git a/tests/ui/confuse-field-and-method/issue-32128.stderr b/tests/ui/confuse-field-and-method/issue-32128.stderr
index 3d860d8c85a..aaec15a41dc 100644
--- a/tests/ui/confuse-field-and-method/issue-32128.stderr
+++ b/tests/ui/confuse-field-and-method/issue-32128.stderr
@@ -7,7 +7,7 @@ LL | struct Example {
 LL |     demo.example(1);
    |          ^^^^^^^ field, not a method
    |
-help: to call the function stored in `example`, surround the field access with parentheses
+help: to call the trait object stored in `example`, surround the field access with parentheses
    |
 LL |     (demo.example)(1);
    |     +            +
diff --git a/tests/ui/confuse-field-and-method/issue-33784.stderr b/tests/ui/confuse-field-and-method/issue-33784.stderr
index 8acd1f8ff1e..59a6f4fccd8 100644
--- a/tests/ui/confuse-field-and-method/issue-33784.stderr
+++ b/tests/ui/confuse-field-and-method/issue-33784.stderr
@@ -4,7 +4,7 @@ error[E0599]: no method named `closure` found for reference `&Obj<{closure@$DIR/
 LL |     p.closure();
    |       ^^^^^^^ field, not a method
    |
-help: to call the function stored in `closure`, surround the field access with parentheses
+help: to call the closure stored in `closure`, surround the field access with parentheses
    |
 LL |     (p.closure)();
    |     +         +
@@ -19,7 +19,7 @@ error[E0599]: no method named `fn_ptr` found for reference `&&Obj<{closure@$DIR/
 LL |     q.fn_ptr();
    |       ^^^^^^ field, not a method
    |
-help: to call the function stored in `fn_ptr`, surround the field access with parentheses
+help: to call the function pointer stored in `fn_ptr`, surround the field access with parentheses
    |
 LL |     (q.fn_ptr)();
    |     +        +
@@ -30,7 +30,7 @@ error[E0599]: no method named `c_fn_ptr` found for reference `&D` in the current
 LL |     s.c_fn_ptr();
    |       ^^^^^^^^ field, not a method
    |
-help: to call the function stored in `c_fn_ptr`, surround the field access with parentheses
+help: to call the function pointer stored in `c_fn_ptr`, surround the field access with parentheses
    |
 LL |     (s.c_fn_ptr)();
    |     +          +
diff --git a/tests/ui/const-generics/generic_const_exprs/bad-multiply.rs b/tests/ui/const-generics/generic_const_exprs/bad-multiply.rs
new file mode 100644
index 00000000000..1af6d5742b1
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/bad-multiply.rs
@@ -0,0 +1,18 @@
+// regression test for #124350
+
+struct Node<const D: usize> {}
+
+impl<const D: usize> Node<D>
+where
+    SmallVec<{ D * 2 }>:,
+    //~^ ERROR generic parameters may not be used in const operations
+    //~| ERROR constant provided when a type was expected
+{
+    fn new() -> Self {
+        Node::new()
+    }
+}
+
+struct SmallVec<T1>(T1);
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr
new file mode 100644
index 00000000000..a8d6cebabe7
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr
@@ -0,0 +1,18 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/bad-multiply.rs:7:16
+   |
+LL |     SmallVec<{ D * 2 }>:,
+   |                ^ cannot perform const operation using `D`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `D`
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error[E0747]: constant provided when a type was expected
+  --> $DIR/bad-multiply.rs:7:14
+   |
+LL |     SmallVec<{ D * 2 }>:,
+   |              ^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/const-generics/kind_mismatch.rs b/tests/ui/const-generics/kind_mismatch.rs
index bab58d5952a..ecdc01a5ef9 100644
--- a/tests/ui/const-generics/kind_mismatch.rs
+++ b/tests/ui/const-generics/kind_mismatch.rs
@@ -20,5 +20,4 @@ pub fn remove_key<K, S: SubsetExcept<K>>() -> S {
 
 fn main() {
     let map: KeyHolder<0> = remove_key::<_, _>();
-    //~^ ERROR: the trait bound `KeyHolder<0>: SubsetExcept<_>` is not satisfied
 }
diff --git a/tests/ui/const-generics/kind_mismatch.stderr b/tests/ui/const-generics/kind_mismatch.stderr
index e13bc6ee058..1487b189619 100644
--- a/tests/ui/const-generics/kind_mismatch.stderr
+++ b/tests/ui/const-generics/kind_mismatch.stderr
@@ -14,26 +14,6 @@ LL | impl<K> ContainsKey<K> for KeyHolder<K> {}
    |      |
    |      help: consider changing this type parameter to a const parameter: `const K: u8`
 
-error[E0277]: the trait bound `KeyHolder<0>: SubsetExcept<_>` is not satisfied
-  --> $DIR/kind_mismatch.rs:22:45
-   |
-LL |     let map: KeyHolder<0> = remove_key::<_, _>();
-   |                                             ^ the trait `ContainsKey<0>` is not implemented for `KeyHolder<0>`
-   |
-note: required for `KeyHolder<0>` to implement `SubsetExcept<_>`
-  --> $DIR/kind_mismatch.rs:15:28
-   |
-LL | impl<P, T: ContainsKey<0>> SubsetExcept<P> for T {}
-   |            --------------  ^^^^^^^^^^^^^^^     ^
-   |            |
-   |            unsatisfied trait bound introduced here
-note: required by a bound in `remove_key`
-  --> $DIR/kind_mismatch.rs:17:25
-   |
-LL | pub fn remove_key<K, S: SubsetExcept<K>>() -> S {
-   |                         ^^^^^^^^^^^^^^^ required by this bound in `remove_key`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0277, E0747.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs
index 61bdf57ffdb..759d2e8b2ed 100644
--- a/tests/ui/consts/const-pattern-irrefutable.rs
+++ b/tests/ui/consts/const-pattern-irrefutable.rs
@@ -1,28 +1,43 @@
 mod foo {
     pub const b: u8 = 2;
-    pub const d: u8 = 2;
+    //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
+    pub const d: (u8, u8) = (2, 1);
+    //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
 }
 
 use foo::b as c;
 use foo::d;
 
 const a: u8 = 2;
+//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
+
+#[derive(PartialEq)]
+struct S {
+    foo: u8,
+}
+
+const e: S = S {
+    foo: 0,
+};
 
 fn main() {
     let a = 4;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     let c = 4;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
-    let d = 4;
+    let d = (4, 4);
     //~^ ERROR refutable pattern in local binding
-    //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
+    //~| patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
+    //~| HELP introduce a variable instead
+    let e = S {
+    //~^ ERROR refutable pattern in local binding
+    //~| pattern `S { foo: 1_u8..=u8::MAX }` not covered
     //~| HELP introduce a variable instead
+        foo: 1,
+    };
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index 2aed68bdd64..afb67a3a118 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -1,45 +1,76 @@
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:12:9
+  --> $DIR/const-pattern-irrefutable.rs:24:9
    |
+LL | const a: u8 = 2;
+   | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
+...
 LL |     let a = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `a_var`
+   |         ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
+help: introduce a variable instead
+   |
+LL |     let a_var = 4;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:17:9
+  --> $DIR/const-pattern-irrefutable.rs:28:9
    |
+LL |     pub const b: u8 = 2;
+   |     --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
+...
 LL |     let c = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `c_var`
+   |         ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
+help: introduce a variable instead
+   |
+LL |     let b_var = 4;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:22:9
+  --> $DIR/const-pattern-irrefutable.rs:32:9
    |
-LL |     let d = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `d_var`
+LL |     pub const d: (u8, u8) = (2, 1);
+   |     --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
+...
+LL |     let d = (4, 4);
+   |         ^ patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `u8`
+   = note: the matched value is of type `(u8, u8)`
+help: introduce a variable instead
+   |
+LL |     let d_var = (4, 4);
+   |         ~~~~~
+
+error[E0005]: refutable pattern in local binding
+  --> $DIR/const-pattern-irrefutable.rs:36:9
+   |
+LL | const e: S = S {
+   | ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable
+...
+LL |     let e = S {
+   |         ^ pattern `S { foo: 1_u8..=u8::MAX }` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `S` defined here
+  --> $DIR/const-pattern-irrefutable.rs:15:8
+   |
+LL | struct S {
+   |        ^
+   = note: the matched value is of type `S`
+help: introduce a variable instead
+   |
+LL |     let e_var = S {
+   |         ~~~~~
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
index bd61f43727b..c73d1f05900 100644
--- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
@@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match &[][..] {
    |           ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         E_SL => {}
+   |         ---- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `E_SL`
    |
    = note: the matched value is of type `&[E]`
+note: constant `E_SL` defined here
+  --> $DIR/incomplete-slice.rs:6:1
+   |
+LL | const E_SL: &[E] = &[E::A];
+   | ^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         E_SL_var => {}
+   |             ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         E_SL => {},
diff --git a/tests/ui/coroutine/async_gen_fn.none.stderr b/tests/ui/coroutine/async_gen_fn.none.stderr
index 047f4d82486..2fc7419ab1c 100644
--- a/tests/ui/coroutine/async_gen_fn.none.stderr
+++ b/tests/ui/coroutine/async_gen_fn.none.stderr
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async gen fn foo() {}
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found `gen`
diff --git a/tests/ui/coroutine/async_gen_fn.rs b/tests/ui/coroutine/async_gen_fn.rs
index e8be0434b9e..b9adeec3f40 100644
--- a/tests/ui/coroutine/async_gen_fn.rs
+++ b/tests/ui/coroutine/async_gen_fn.rs
@@ -1,5 +1,5 @@
 //@ revisions: e2024 none
-//@[e2024] compile-flags: --edition 2024 -Zunstable-options
+//@[e2024] edition: 2024
 
 async gen fn foo() {}
 //[none]~^ ERROR: `async fn` is not permitted in Rust 2015
diff --git a/tests/ui/coroutine/async_gen_fn_iter.rs b/tests/ui/coroutine/async_gen_fn_iter.rs
index 42288712c70..3f7e7aa0ac2 100644
--- a/tests/ui/coroutine/async_gen_fn_iter.rs
+++ b/tests/ui/coroutine/async_gen_fn_iter.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ run-pass
 
 #![feature(gen_blocks, async_iterator)]
diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs
index 97c3d06c023..d0597fdd8e1 100644
--- a/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs
+++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Z unstable-options
 
 #![feature(gen_blocks)]
 #![feature(async_closure)]
diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr
index 77dc214bcec..bdd26d39d82 100644
--- a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr
+++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr
@@ -1,5 +1,5 @@
 error[E0267]: `break` inside `async` function
-  --> $DIR/break-inside-coroutine-issue-124495.rs:8:5
+  --> $DIR/break-inside-coroutine-issue-124495.rs:7:5
    |
 LL | async fn async_fn() {
    | ------------------- enclosing `async` function
@@ -7,7 +7,7 @@ LL |     break;
    |     ^^^^^ cannot `break` inside `async` function
 
 error[E0267]: `break` inside `gen` function
-  --> $DIR/break-inside-coroutine-issue-124495.rs:12:5
+  --> $DIR/break-inside-coroutine-issue-124495.rs:11:5
    |
 LL | gen fn gen_fn() {
    | --------------- enclosing `gen` function
@@ -15,7 +15,7 @@ LL |     break;
    |     ^^^^^ cannot `break` inside `gen` function
 
 error[E0267]: `break` inside `async gen` function
-  --> $DIR/break-inside-coroutine-issue-124495.rs:16:5
+  --> $DIR/break-inside-coroutine-issue-124495.rs:15:5
    |
 LL | async gen fn async_gen_fn() {
    | --------------------------- enclosing `async gen` function
@@ -23,7 +23,7 @@ LL |     break;
    |     ^^^^^ cannot `break` inside `async gen` function
 
 error[E0267]: `break` inside `async` block
-  --> $DIR/break-inside-coroutine-issue-124495.rs:20:21
+  --> $DIR/break-inside-coroutine-issue-124495.rs:19:21
    |
 LL |     let _ = async { break; };
    |             -----   ^^^^^ cannot `break` inside `async` block
@@ -31,7 +31,7 @@ LL |     let _ = async { break; };
    |             enclosing `async` block
 
 error[E0267]: `break` inside `async` closure
-  --> $DIR/break-inside-coroutine-issue-124495.rs:22:24
+  --> $DIR/break-inside-coroutine-issue-124495.rs:21:24
    |
 LL |     let _ = async || { break; };
    |             --------   ^^^^^ cannot `break` inside `async` closure
@@ -39,7 +39,7 @@ LL |     let _ = async || { break; };
    |             enclosing `async` closure
 
 error[E0267]: `break` inside `gen` block
-  --> $DIR/break-inside-coroutine-issue-124495.rs:24:19
+  --> $DIR/break-inside-coroutine-issue-124495.rs:23:19
    |
 LL |     let _ = gen { break; };
    |             ---   ^^^^^ cannot `break` inside `gen` block
@@ -47,7 +47,7 @@ LL |     let _ = gen { break; };
    |             enclosing `gen` block
 
 error[E0267]: `break` inside `async gen` block
-  --> $DIR/break-inside-coroutine-issue-124495.rs:26:25
+  --> $DIR/break-inside-coroutine-issue-124495.rs:25:25
    |
 LL |     let _ = async gen { break; };
    |             ---------   ^^^^^ cannot `break` inside `async gen` block
diff --git a/tests/ui/coroutine/const_gen_fn.rs b/tests/ui/coroutine/const_gen_fn.rs
index 986693f33ab..2701139ffed 100644
--- a/tests/ui/coroutine/const_gen_fn.rs
+++ b/tests/ui/coroutine/const_gen_fn.rs
@@ -1,5 +1,4 @@
 //@ edition:2024
-//@ compile-flags: -Zunstable-options
 
 #![feature(gen_blocks)]
 
diff --git a/tests/ui/coroutine/const_gen_fn.stderr b/tests/ui/coroutine/const_gen_fn.stderr
index b58446ac88f..4f3c73d1678 100644
--- a/tests/ui/coroutine/const_gen_fn.stderr
+++ b/tests/ui/coroutine/const_gen_fn.stderr
@@ -1,5 +1,5 @@
 error: functions cannot be both `const` and `gen`
-  --> $DIR/const_gen_fn.rs:6:1
+  --> $DIR/const_gen_fn.rs:5:1
    |
 LL | const gen fn a() {}
    | ^^^^^-^^^----------
@@ -8,7 +8,7 @@ LL | const gen fn a() {}
    | `const` because of this
 
 error: functions cannot be both `const` and `async gen`
-  --> $DIR/const_gen_fn.rs:9:1
+  --> $DIR/const_gen_fn.rs:8:1
    |
 LL | const async gen fn b() {}
    | ^^^^^-^^^^^^^^^----------
diff --git a/tests/ui/coroutine/gen_block.rs b/tests/ui/coroutine/gen_block.rs
index 7e87a572b90..6734de3b667 100644
--- a/tests/ui/coroutine/gen_block.rs
+++ b/tests/ui/coroutine/gen_block.rs
@@ -1,5 +1,5 @@
 //@ revisions: e2024 none
-//@[e2024] compile-flags: --edition 2024 -Zunstable-options
+//@[e2024] edition: 2024
 #![cfg_attr(e2024, feature(gen_blocks))]
 #![feature(stmt_expr_attributes)]
 
diff --git a/tests/ui/coroutine/gen_block_is_coro.rs b/tests/ui/coroutine/gen_block_is_coro.rs
index c98e1e60388..bccc3e86ee4 100644
--- a/tests/ui/coroutine/gen_block_is_coro.rs
+++ b/tests/ui/coroutine/gen_block_is_coro.rs
@@ -1,4 +1,5 @@
-//@compile-flags: --edition 2024 -Zunstable-options --diagnostic-width=300
+//@ edition: 2024
+//@ compile-flags: --diagnostic-width=300
 #![feature(coroutines, coroutine_trait, gen_blocks)]
 
 use std::ops::Coroutine;
diff --git a/tests/ui/coroutine/gen_block_is_coro.stderr b/tests/ui/coroutine/gen_block_is_coro.stderr
index 083e738f3ec..444f0eca1d5 100644
--- a/tests/ui/coroutine/gen_block_is_coro.stderr
+++ b/tests/ui/coroutine/gen_block_is_coro.stderr
@@ -1,26 +1,26 @@
-error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}: Coroutine` is not satisfied
-  --> $DIR/gen_block_is_coro.rs:6:13
+error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:8:5: 8:8}: Coroutine` is not satisfied
+  --> $DIR/gen_block_is_coro.rs:7:13
    |
 LL | fn foo() -> impl Coroutine<Yield = u32, Return = ()> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:8:5: 8:8}`
 LL |     gen { yield 42 }
-   |     ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:7:5: 7:8}` here
+   |     ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:8:5: 8:8}` here
 
-error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}: Coroutine` is not satisfied
-  --> $DIR/gen_block_is_coro.rs:10:13
+error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:12:5: 12:8}: Coroutine` is not satisfied
+  --> $DIR/gen_block_is_coro.rs:11:13
    |
 LL | fn bar() -> impl Coroutine<Yield = i64, Return = ()> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:12:5: 12:8}`
 LL |     gen { yield 42 }
-   |     ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:11:5: 11:8}` here
+   |     ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:12:5: 12:8}` here
 
-error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}: Coroutine` is not satisfied
-  --> $DIR/gen_block_is_coro.rs:14:13
+error[E0277]: the trait bound `{gen block@$DIR/gen_block_is_coro.rs:16:5: 16:8}: Coroutine` is not satisfied
+  --> $DIR/gen_block_is_coro.rs:15:13
    |
 LL | fn baz() -> impl Coroutine<Yield = i32, Return = ()> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine` is not implemented for `{gen block@$DIR/gen_block_is_coro.rs:16:5: 16:8}`
 LL |     gen { yield 42 }
-   |     ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:15:5: 15:8}` here
+   |     ---------------- return type was inferred to be `{gen block@$DIR/gen_block_is_coro.rs:16:5: 16:8}` here
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/coroutine/gen_block_is_fused_iter.rs b/tests/ui/coroutine/gen_block_is_fused_iter.rs
index f3e19a7f54f..e4eab6195ee 100644
--- a/tests/ui/coroutine/gen_block_is_fused_iter.rs
+++ b/tests/ui/coroutine/gen_block_is_fused_iter.rs
@@ -1,5 +1,5 @@
 //@ revisions: next old
-//@compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 //@[next] compile-flags: -Znext-solver
 //@ check-pass
 #![feature(gen_blocks)]
diff --git a/tests/ui/coroutine/gen_block_is_iter.rs b/tests/ui/coroutine/gen_block_is_iter.rs
index 396d7737132..032360fbee0 100644
--- a/tests/ui/coroutine/gen_block_is_iter.rs
+++ b/tests/ui/coroutine/gen_block_is_iter.rs
@@ -1,5 +1,5 @@
 //@ revisions: next old
-//@compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 //@[next] compile-flags: -Znext-solver
 //@ check-pass
 #![feature(gen_blocks)]
diff --git a/tests/ui/coroutine/gen_block_is_no_future.rs b/tests/ui/coroutine/gen_block_is_no_future.rs
index a5bb8533719..eca8a9b6320 100644
--- a/tests/ui/coroutine/gen_block_is_no_future.rs
+++ b/tests/ui/coroutine/gen_block_is_no_future.rs
@@ -1,4 +1,4 @@
-//@compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 #![feature(gen_blocks)]
 
 fn foo() -> impl std::future::Future { //~ ERROR is not a future
diff --git a/tests/ui/coroutine/gen_block_iterate.rs b/tests/ui/coroutine/gen_block_iterate.rs
index a9cb5ef3e2c..afeb56cc2f3 100644
--- a/tests/ui/coroutine/gen_block_iterate.rs
+++ b/tests/ui/coroutine/gen_block_iterate.rs
@@ -1,5 +1,5 @@
 //@ revisions: next old
-//@compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 //@[next] compile-flags: -Znext-solver
 //@ run-pass
 #![feature(gen_blocks)]
diff --git a/tests/ui/coroutine/gen_block_move.fixed b/tests/ui/coroutine/gen_block_move.fixed
index 0327ca75f9e..e58c9b3f9fe 100644
--- a/tests/ui/coroutine/gen_block_move.fixed
+++ b/tests/ui/coroutine/gen_block_move.fixed
@@ -1,4 +1,4 @@
-//@ compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 //@ run-rustfix
 #![feature(gen_blocks)]
 
diff --git a/tests/ui/coroutine/gen_block_move.rs b/tests/ui/coroutine/gen_block_move.rs
index 53d0149872a..e249404a0a1 100644
--- a/tests/ui/coroutine/gen_block_move.rs
+++ b/tests/ui/coroutine/gen_block_move.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 //@ run-rustfix
 #![feature(gen_blocks)]
 
diff --git a/tests/ui/coroutine/gen_block_panic.rs b/tests/ui/coroutine/gen_block_panic.rs
index ada56a5bd6f..b6362d5046a 100644
--- a/tests/ui/coroutine/gen_block_panic.rs
+++ b/tests/ui/coroutine/gen_block_panic.rs
@@ -1,4 +1,4 @@
-//@compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 //@ run-pass
 //@ needs-unwind
 #![feature(gen_blocks)]
diff --git a/tests/ui/coroutine/gen_fn.rs b/tests/ui/coroutine/gen_fn.rs
index d47b7e576d0..2f50d5db9ac 100644
--- a/tests/ui/coroutine/gen_fn.rs
+++ b/tests/ui/coroutine/gen_fn.rs
@@ -1,5 +1,5 @@
 //@ revisions: e2024 none
-//@[e2024] compile-flags: --edition 2024 -Zunstable-options
+//@[e2024] edition: 2024
 
 gen fn foo() {}
 //[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
diff --git a/tests/ui/coroutine/gen_fn_iter.rs b/tests/ui/coroutine/gen_fn_iter.rs
index ae09d678fe3..9cd75551ad4 100644
--- a/tests/ui/coroutine/gen_fn_iter.rs
+++ b/tests/ui/coroutine/gen_fn_iter.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ run-pass
 #![feature(gen_blocks)]
 
diff --git a/tests/ui/coroutine/gen_fn_lifetime_capture.rs b/tests/ui/coroutine/gen_fn_lifetime_capture.rs
index 517096d092e..bee6c2e8803 100644
--- a/tests/ui/coroutine/gen_fn_lifetime_capture.rs
+++ b/tests/ui/coroutine/gen_fn_lifetime_capture.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ check-pass
 #![feature(gen_blocks)]
 
diff --git a/tests/ui/coroutine/other-attribute-on-gen.rs b/tests/ui/coroutine/other-attribute-on-gen.rs
index 0f26dc6860d..5f4584ee022 100644
--- a/tests/ui/coroutine/other-attribute-on-gen.rs
+++ b/tests/ui/coroutine/other-attribute-on-gen.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ run-pass
 #![feature(gen_blocks)]
 #![feature(optimize_attribute)]
diff --git a/tests/ui/coroutine/return-types-diverge.rs b/tests/ui/coroutine/return-types-diverge.rs
index 5b639eea09a..7aa8fc028ce 100644
--- a/tests/ui/coroutine/return-types-diverge.rs
+++ b/tests/ui/coroutine/return-types-diverge.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 //@ check-pass
 
 #![feature(gen_blocks)]
diff --git a/tests/ui/coroutine/return-types.rs b/tests/ui/coroutine/return-types.rs
index ad2080fd88b..4fecc550531 100644
--- a/tests/ui/coroutine/return-types.rs
+++ b/tests/ui/coroutine/return-types.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 
 #![feature(gen_blocks)]
 
diff --git a/tests/ui/coroutine/self_referential_gen_block.rs b/tests/ui/coroutine/self_referential_gen_block.rs
index dccd83768c4..322cbf4f18a 100644
--- a/tests/ui/coroutine/self_referential_gen_block.rs
+++ b/tests/ui/coroutine/self_referential_gen_block.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: --edition 2024 -Zunstable-options
+//@ edition: 2024
 #![feature(gen_blocks)]
 //! This test checks that we don't allow self-referential generators
 
diff --git a/tests/ui/diagnostic-width/E0271.rs b/tests/ui/diagnostic-width/E0271.rs
index ce41ad2952b..dedae4365e8 100644
--- a/tests/ui/diagnostic-width/E0271.rs
+++ b/tests/ui/diagnostic-width/E0271.rs
@@ -1,6 +1,6 @@
 //@ revisions: ascii unicode
 //@[ascii] compile-flags: --diagnostic-width=40
-//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=40
+//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40
 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
 trait Future {
     type Error;
diff --git a/tests/ui/diagnostic-width/flag-human.rs b/tests/ui/diagnostic-width/flag-human.rs
index 1af41659141..8e656293b41 100644
--- a/tests/ui/diagnostic-width/flag-human.rs
+++ b/tests/ui/diagnostic-width/flag-human.rs
@@ -1,6 +1,6 @@
 //@ revisions: ascii unicode
 //@[ascii] compile-flags: --diagnostic-width=20
-//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=20
+//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=20
 
 // This test checks that `-Z output-width` effects the human error output by restricting it to an
 // arbitrarily low value so that the effect is visible.
diff --git a/tests/ui/diagnostic-width/long-E0308.rs b/tests/ui/diagnostic-width/long-E0308.rs
index 73f81f5872a..695852f83ac 100644
--- a/tests/ui/diagnostic-width/long-E0308.rs
+++ b/tests/ui/diagnostic-width/long-E0308.rs
@@ -1,6 +1,6 @@
 //@ revisions: ascii unicode
 //@[ascii] compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
-//@[unicode] compile-flags: -Zunstable-options=yes --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
+//@[unicode] compile-flags: -Zunstable-options --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes
 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
 
 mod a {
diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
index 61c4b31e03a..e630db8ba42 100644
--- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
+++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
@@ -1,5 +1,5 @@
 //@ revisions: ascii unicode
-//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode
+//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode
 // ignore-tidy-linelength
 
 fn main() {
diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs
index 283506bd6c9..de2f42a4a72 100644
--- a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs
+++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs
@@ -1,5 +1,5 @@
 //@ revisions: ascii unicode
-//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode
+//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode
 // ignore-tidy-linelength
 
 fn main() {
diff --git a/tests/ui/drop/auxiliary/edition-2024-macros.rs b/tests/ui/drop/auxiliary/edition-2024-macros.rs
index 236340bfed4..44befbc9843 100644
--- a/tests/ui/drop/auxiliary/edition-2024-macros.rs
+++ b/tests/ui/drop/auxiliary/edition-2024-macros.rs
@@ -1,5 +1,4 @@
 //@ edition:2024
-//@ compile-flags: -Zunstable-options
 
 #[macro_export]
 macro_rules! edition_2024_block {
diff --git a/tests/ui/drop/drop_order_if_let_rescope.rs b/tests/ui/drop/drop_order_if_let_rescope.rs
index cea84bbaa2b..7445e3a6a5f 100644
--- a/tests/ui/drop/drop_order_if_let_rescope.rs
+++ b/tests/ui/drop/drop_order_if_let_rescope.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 //@ edition:2024
-//@ compile-flags: -Z validate-mir -Zunstable-options
+//@ compile-flags: -Z validate-mir
 
 #![feature(let_chains)]
 
diff --git a/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs
index e055c20d777..a3583c48c39 100644
--- a/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs
+++ b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs
@@ -1,5 +1,5 @@
 //@ edition: 2024
-//@ compile-flags: -Z validate-mir -Zunstable-options
+//@ compile-flags: -Z validate-mir
 
 #![deny(if_let_rescope)]
 
diff --git a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
index fde542c756f..361862100e6 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
@@ -1,9 +1,9 @@
-// This test is to demonstrate that the lint is gated behind Edition and
-// is triggered only for Edition 2021 and before.
+// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is used
+// because this is a migration lint.
+// Only `cargo fix --edition 2024` shall activate this lint.
 
 //@ check-pass
 //@ edition: 2024
-//@ compile-flags: -Z unstable-options
 
 #![deny(tail_expr_drop_order)]
 
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs
index d61abae5187..0fabc1f085c 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order.rs
@@ -1,13 +1,26 @@
-//@ edition: 2021
-
 // Edition 2024 lint for change in drop order at tail expression
 // This lint is to capture potential change in program semantics
 // due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606>
+//@ edition: 2021
+//@ build-fail
 
-#![deny(tail_expr_drop_order)]
+#![deny(tail_expr_drop_order)] //~ NOTE: the lint level is defined here
+#![allow(dropping_copy_types)]
 
 struct LoudDropper;
 impl Drop for LoudDropper {
+    //~^ NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
+    //~| NOTE: `future` invokes this custom destructor
+    //~| NOTE: `_x` invokes this custom destructor
+    //~| NOTE: `#1` invokes this custom destructor
     fn drop(&mut self) {
         // This destructor should be considered significant because it is a custom destructor
         // and we will assume that the destructor can generate side effects arbitrarily so that
@@ -23,30 +36,70 @@ impl LoudDropper {
 
 fn should_lint() -> i32 {
     let x = LoudDropper;
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
     // Should lint
     x.get() + LoudDropper.get()
-    //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
     //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
 }
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 
-fn should_lint_closure() -> impl FnOnce() -> i32 {
+fn should_not_lint_closure() -> impl FnOnce() -> i32 {
     let x = LoudDropper;
-    move || x.get() + LoudDropper.get()
-    //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-    //~| WARN: this changes meaning in Rust 2024
+    move || {
+        // Should not lint because ...
+        x.get() + LoudDropper.get()
+    }
+    // ^ closure captures like `x` are always dropped last by contract
+}
+
+fn should_lint_in_nested_items() {
+    fn should_lint_me() -> i32 {
+        let x = LoudDropper;
+        //~^ NOTE: `x` calls a custom destructor
+        //~| NOTE: `x` will be dropped later as of Edition 2024
+        // Should lint
+        x.get() + LoudDropper.get()
+        //~^ ERROR: relative drop order changing in Rust 2024
+        //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+        //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+        //~| WARN: this changes meaning in Rust 2024
+        //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+        //~| NOTE: for more information, see issue #123739
+    }
+    //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 }
 
+fn should_not_lint_params(x: LoudDropper) -> i32 {
+    // Should not lint because ...
+    x.get() + LoudDropper.get()
+}
+// ^ function parameters like `x` are always dropped last
+
 fn should_not_lint() -> i32 {
     let x = LoudDropper;
     // Should not lint
     x.get()
 }
 
-fn should_not_lint_in_nested_block() -> i32 {
+fn should_lint_in_nested_block() -> i32 {
     let x = LoudDropper;
-    // Should not lint because Edition 2021 drops temporaries in blocks earlier already
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
     { LoudDropper.get() }
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
 }
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 
 fn should_not_lint_in_match_arm() -> i32 {
     let x = LoudDropper;
@@ -56,14 +109,144 @@ fn should_not_lint_in_match_arm() -> i32 {
     }
 }
 
-fn should_lint_in_nested_items() {
-    fn should_lint_me() -> i32 {
+fn should_not_lint_when_consumed() -> (LoudDropper, i32) {
+    let x = LoudDropper;
+    // Should not lint because `LoudDropper` is consumed by the return value
+    (LoudDropper, x.get())
+}
+
+struct MyAdt {
+    a: LoudDropper,
+    b: LoudDropper,
+}
+
+fn should_not_lint_when_consumed_in_ctor() -> MyAdt {
+    let a = LoudDropper;
+    // Should not lint
+    MyAdt { a, b: LoudDropper }
+}
+
+fn should_not_lint_when_moved() -> i32 {
+    let x = LoudDropper;
+    drop(x);
+    // Should not lint because `x` is not live
+    LoudDropper.get()
+}
+
+fn should_lint_into_async_body() -> i32 {
+    async fn f() {
+        async fn f() {}
         let x = LoudDropper;
-        // Should lint
-        x.get() + LoudDropper.get()
-        //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-        //~| WARN: this changes meaning in Rust 2024
+        f().await;
+        drop(x);
+    }
+
+    let future = f();
+    //~^ NOTE: `future` calls a custom destructor
+    //~| NOTE: `future` will be dropped later as of Edition 2024
+    LoudDropper.get()
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_lint_generics<T: Default>() -> &'static str {
+    fn extract<T>(_: &T) -> &'static str {
+        todo!()
+    }
+    let x = T::default();
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
+    extract(&T::default())
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_lint_adt() -> i32 {
+    let x: Result<LoudDropper, ()> = Ok(LoudDropper);
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
+    LoudDropper.get()
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_not_lint_insign_dtor() -> i32 {
+    let x = String::new();
+    LoudDropper.get()
+}
+
+fn should_lint_with_dtor_span() -> i32 {
+    struct LoudDropper3;
+    impl Drop for LoudDropper3 {
+        //~^ NOTE: `#1` invokes this custom destructor
+        fn drop(&mut self) {
+            println!("loud drop");
+        }
     }
+    impl LoudDropper3 {
+        fn get(&self) -> i32 {
+            0
+        }
+    }
+    struct LoudDropper2;
+    impl Drop for LoudDropper2 {
+        //~^ NOTE: `x` invokes this custom destructor
+        fn drop(&mut self) {
+            println!("loud drop");
+        }
+    }
+    impl LoudDropper2 {
+        fn get(&self) -> i32 {
+            0
+        }
+    }
+
+    let x = LoudDropper2;
+    //~^ NOTE: `x` calls a custom destructor
+    //~| NOTE: `x` will be dropped later as of Edition 2024
+    LoudDropper3.get()
+    //~^ ERROR: relative drop order changing in Rust 2024
+    //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+    //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+    //~| WARN: this changes meaning in Rust 2024
+    //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+    //~| NOTE: for more information, see issue #123739
+}
+//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
+
+fn should_lint_with_transient_drops() {
+    drop((
+        {
+            LoudDropper.get()
+            //~^ ERROR: relative drop order changing in Rust 2024
+            //~| NOTE: this value will be stored in a temporary; let us call it `#1`
+            //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+            //~| WARN: this changes meaning in Rust 2024
+            //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects
+            //~| NOTE: for more information, see issue #123739
+        },
+        {
+            let _x = LoudDropper;
+            //~^ NOTE: `_x` calls a custom destructor
+            //~| NOTE: `_x` will be dropped later as of Edition 2024
+        },
+    ));
+    //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement
 }
 
 fn main() {}
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr
index 6775c4ce6d1..f0da24605e6 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.stderr
+++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr
@@ -1,42 +1,335 @@
-error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:27:15
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:42:15
    |
 LL |     let x = LoudDropper;
-   |         - these values have significant drop implementation and will observe changes in drop order under Edition 2024
-LL |     // Should lint
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
 LL |     x.get() + LoudDropper.get()
    |               ^^^^^^^^^^^
+   |               |
+   |               this value will be stored in a temporary; let us call it `#1`
+   |               up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 note: the lint level is defined here
   --> $DIR/lint-tail-expr-drop-order.rs:7:9
    |
 LL | #![deny(tail_expr_drop_order)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:34:23
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:67:19
+   |
+LL |         let x = LoudDropper;
+   |             -
+   |             |
+   |             `x` calls a custom destructor
+   |             `x` will be dropped later as of Edition 2024
+...
+LL |         x.get() + LoudDropper.get()
+   |                   ^^^^^^^^^^^
+   |                   |
+   |                   this value will be stored in a temporary; let us call it `#1`
+   |                   up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL |     }
+   |     - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:94:7
    |
 LL |     let x = LoudDropper;
-   |         - these values have significant drop implementation and will observe changes in drop order under Edition 2024
-LL |     move || x.get() + LoudDropper.get()
-   |                       ^^^^^^^^^^^
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     { LoudDropper.get() }
+   |       ^^^^^^^^^^^
+   |       |
+   |       this value will be stored in a temporary; let us call it `#1`
+   |       up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
-error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
-  --> $DIR/lint-tail-expr-drop-order.rs:63:19
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:147:5
    |
-LL |         let x = LoudDropper;
-   |             - these values have significant drop implementation and will observe changes in drop order under Edition 2024
-LL |         // Should lint
-LL |         x.get() + LoudDropper.get()
-   |                   ^^^^^^^^^^^
+LL |     let future = f();
+   |         ------
+   |         |
+   |         `future` calls a custom destructor
+   |         `future` will be dropped later as of Edition 2024
+...
+LL |     LoudDropper.get()
+   |     ^^^^^^^^^^^
+   |     |
+   |     this value will be stored in a temporary; let us call it `#1`
+   |     up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `future` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:164:14
+   |
+LL |     let x = T::default();
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     extract(&T::default())
+   |              ^^^^^^^^^^^^
+   |              |
+   |              this value will be stored in a temporary; let us call it `#1`
+   |              up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:178:5
+   |
+LL |     let x: Result<LoudDropper, ()> = Ok(LoudDropper);
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     LoudDropper.get()
+   |     ^^^^^^^^^^^
+   |     |
+   |     this value will be stored in a temporary; let us call it `#1`
+   |     up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:222:5
+   |
+LL |     let x = LoudDropper2;
+   |         -
+   |         |
+   |         `x` calls a custom destructor
+   |         `x` will be dropped later as of Edition 2024
+...
+LL |     LoudDropper3.get()
+   |     ^^^^^^^^^^^^
+   |     |
+   |     this value will be stored in a temporary; let us call it `#1`
+   |     up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL | }
+   | - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:195:5
+   |
+LL | /     impl Drop for LoudDropper3 {
+LL | |
+LL | |         fn drop(&mut self) {
+LL | |             println!("loud drop");
+LL | |         }
+LL | |     }
+   | |_____^
+note: `x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:207:5
+   |
+LL | /     impl Drop for LoudDropper2 {
+LL | |
+LL | |         fn drop(&mut self) {
+LL | |             println!("loud drop");
+LL | |         }
+LL | |     }
+   | |_____^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
+
+error: relative drop order changing in Rust 2024
+  --> $DIR/lint-tail-expr-drop-order.rs:235:13
+   |
+LL |             LoudDropper.get()
+   |             ^^^^^^^^^^^
+   |             |
+   |             this value will be stored in a temporary; let us call it `#1`
+   |             up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024
+...
+LL |             let _x = LoudDropper;
+   |                 --
+   |                 |
+   |                 `_x` calls a custom destructor
+   |                 `_x` will be dropped later as of Edition 2024
+...
+LL |     ));
+   |       - now the temporary value is dropped here, before the local variables in the block or statement
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
+note: `#1` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+note: `_x` invokes this custom destructor
+  --> $DIR/lint-tail-expr-drop-order.rs:11:1
+   |
+LL | / impl Drop for LoudDropper {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
-error: aborting due to 3 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/drop/tail-expr-drop-order.rs b/tests/ui/drop/tail-expr-drop-order.rs
index 80968b823f9..f74530fce1e 100644
--- a/tests/ui/drop/tail-expr-drop-order.rs
+++ b/tests/ui/drop/tail-expr-drop-order.rs
@@ -1,6 +1,6 @@
 //@ aux-build:edition-2021-macros.rs
 //@ aux-build:edition-2024-macros.rs
-//@ compile-flags: -Z validate-mir -Zunstable-options
+//@ compile-flags: -Z validate-mir
 //@ edition: 2024
 //@ run-pass
 
diff --git a/tests/ui/dyn-star/async-block-dyn-star.rs b/tests/ui/dyn-star/async-block-dyn-star.rs
new file mode 100644
index 00000000000..9bffd6c6725
--- /dev/null
+++ b/tests/ui/dyn-star/async-block-dyn-star.rs
@@ -0,0 +1,9 @@
+//@ edition:2018
+
+#![feature(dyn_star, const_async_blocks)]
+//~^ WARN the feature `dyn_star` is incomplete
+
+static S: dyn* Send + Sync = async { 42 };
+//~^ needs to have the same ABI as a pointer
+
+pub fn main() {}
diff --git a/tests/ui/dyn-star/async-block-dyn-star.stderr b/tests/ui/dyn-star/async-block-dyn-star.stderr
new file mode 100644
index 00000000000..f62c85c0ad2
--- /dev/null
+++ b/tests/ui/dyn-star/async-block-dyn-star.stderr
@@ -0,0 +1,20 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/async-block-dyn-star.rs:3:12
+   |
+LL | #![feature(dyn_star, const_async_blocks)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer
+  --> $DIR/async-block-dyn-star.rs:6:30
+   |
+LL | static S: dyn* Send + Sync = async { 42 };
+   |                              ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
index 7b5ea7bb707..a0aff69f396 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
@@ -1,14 +1,17 @@
 error[E0277]: `&T` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
    |
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
+   |                - this type parameter needs to be `Sized`
 LL |     dyn_debug(t);
    |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerLike` is not implemented for `&T`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   = note: required for `&T` to implement `PointerLike`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
+LL + fn polymorphic<T: Debug>(t: &T) {
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
-   |                                          +++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
index 7b5ea7bb707..a0aff69f396 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
@@ -1,14 +1,17 @@
 error[E0277]: `&T` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
    |
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
+   |                - this type parameter needs to be `Sized`
 LL |     dyn_debug(t);
    |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerLike` is not implemented for `&T`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   = note: required for `&T` to implement `PointerLike`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
+LL + fn polymorphic<T: Debug>(t: &T) {
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
-   |                                          +++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-star/drop.rs b/tests/ui/dyn-star/drop.rs
index ca86f1b5b01..bc746331527 100644
--- a/tests/ui/dyn-star/drop.rs
+++ b/tests/ui/dyn-star/drop.rs
@@ -1,13 +1,18 @@
 //@ run-pass
 //@ check-run-results
-#![feature(dyn_star)]
+#![feature(dyn_star, pointer_like_trait)]
 #![allow(incomplete_features)]
 
 use std::fmt::Debug;
+use std::marker::PointerLike;
 
 #[derive(Debug)]
+#[repr(transparent)]
 struct Foo(#[allow(dead_code)] usize);
 
+// FIXME(dyn_star): Make this into a derive.
+impl PointerLike for Foo {}
+
 impl Drop for Foo {
     fn drop(&mut self) {
         println!("destructor called");
diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs
index 6e895e9527a..3cc7390eb12 100644
--- a/tests/ui/dyn-star/enum-cast.rs
+++ b/tests/ui/dyn-star/enum-cast.rs
@@ -3,13 +3,18 @@
 // This used to ICE, because the compiler confused a pointer-like to dyn* coercion
 // with a c-like enum to integer cast.
 
-#![feature(dyn_star)]
+#![feature(dyn_star, pointer_like_trait)]
 #![expect(incomplete_features)]
 
+use std::marker::PointerLike;
+
+#[repr(transparent)]
 enum E {
     Num(usize),
 }
 
+impl PointerLike for E {}
+
 trait Trait {}
 impl Trait for E {}
 
diff --git a/tests/ui/dyn-star/error.rs b/tests/ui/dyn-star/error.rs
index d8261387efa..7288596f3fa 100644
--- a/tests/ui/dyn-star/error.rs
+++ b/tests/ui/dyn-star/error.rs
@@ -7,7 +7,7 @@ trait Foo {}
 
 fn make_dyn_star() {
     let i = 42;
-    let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied
+    let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr
index a9f4a054519..55981c03bac 100644
--- a/tests/ui/dyn-star/error.stderr
+++ b/tests/ui/dyn-star/error.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `{integer}: Foo` is not satisfied
+error[E0277]: the trait bound `usize: Foo` is not satisfied
   --> $DIR/error.rs:10:27
    |
 LL |     let dyn_i: dyn* Foo = i;
-   |                           ^ the trait `Foo` is not implemented for `{integer}`
+   |                           ^ the trait `Foo` is not implemented for `usize`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/error.rs:6:1
diff --git a/tests/ui/dyn-star/float-as-dyn-star.rs b/tests/ui/dyn-star/float-as-dyn-star.rs
new file mode 100644
index 00000000000..1b629c64c25
--- /dev/null
+++ b/tests/ui/dyn-star/float-as-dyn-star.rs
@@ -0,0 +1,16 @@
+//@ only-x86_64
+
+#![feature(dyn_star, pointer_like_trait)]
+//~^ WARN the feature `dyn_star` is incomplete
+
+use std::fmt::Debug;
+use std::marker::PointerLike;
+
+fn make_dyn_star() -> dyn* Debug + 'static {
+    f32::from_bits(0x1) as f64
+    //~^ ERROR `f64` needs to have the same ABI as a pointer
+}
+
+fn main() {
+    println!("{:?}", make_dyn_star());
+}
diff --git a/tests/ui/dyn-star/float-as-dyn-star.stderr b/tests/ui/dyn-star/float-as-dyn-star.stderr
new file mode 100644
index 00000000000..9caba512e5f
--- /dev/null
+++ b/tests/ui/dyn-star/float-as-dyn-star.stderr
@@ -0,0 +1,21 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/float-as-dyn-star.rs:3:12
+   |
+LL | #![feature(dyn_star, pointer_like_trait)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `f64` needs to have the same ABI as a pointer
+  --> $DIR/float-as-dyn-star.rs:10:5
+   |
+LL |     f32::from_bits(0x1) as f64
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `f64`
+   = help: the trait `PointerLike` is implemented for `usize`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr
index adef9525bf1..801e1c233c1 100644
--- a/tests/ui/dyn-star/upcast.stderr
+++ b/tests/ui/dyn-star/upcast.stderr
@@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)]
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
+error[E0277]: `W` needs to have the same ABI as a pointer
+  --> $DIR/upcast.rs:28:23
+   |
+LL |     let w: dyn* Foo = W(0);
+   |                       ^^^^ `W` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `W`
+
 error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer
   --> $DIR/upcast.rs:30:23
    |
@@ -15,6 +23,6 @@ LL |     let w: dyn* Bar = w;
    |
    = help: the trait `PointerLike` is not implemented for `dyn* Foo`
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/editions/async-block-2015.rs b/tests/ui/editions/async-block-2015.rs
index 3daf4930c5b..a079b4aad91 100644
--- a/tests/ui/editions/async-block-2015.rs
+++ b/tests/ui/editions/async-block-2015.rs
@@ -1,7 +1,7 @@
 async fn foo() {
 //~^ ERROR `async fn` is not permitted in Rust 2015
 //~| NOTE to use `async fn`, switch to Rust 2018 or later
-//~| HELP pass `--edition 2021` to `rustc`
+//~| HELP pass `--edition 2024` to `rustc`
 //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 
     let x = async {};
@@ -11,7 +11,7 @@ async fn foo() {
         let x = 42;
         //~^ ERROR expected identifier, found keyword `let`
         //~| NOTE expected identifier, found keyword
-        //~| HELP pass `--edition 2021` to `rustc`
+        //~| HELP pass `--edition 2024` to `rustc`
         //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
         42
     };
@@ -19,7 +19,7 @@ async fn foo() {
         42
         //~^ ERROR expected identifier, found `42`
         //~| NOTE expected identifier
-        //~| HELP pass `--edition 2021` to `rustc`
+        //~| HELP pass `--edition 2024` to `rustc`
         //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
     };
     y.await;
diff --git a/tests/ui/editions/async-block-2015.stderr b/tests/ui/editions/async-block-2015.stderr
index b792b8c1e0d..574bcacc1cf 100644
--- a/tests/ui/editions/async-block-2015.stderr
+++ b/tests/ui/editions/async-block-2015.stderr
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL | async fn foo() {
    | ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected identifier, found keyword `let`
@@ -15,7 +15,7 @@ LL |     let y = async {
 LL |         let x = 42;
    |         ^^^ expected identifier, found keyword
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected identifier, found `42`
@@ -26,7 +26,7 @@ LL |     let z = async {
 LL |         42
    |         ^^ expected identifier
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0422]: cannot find struct, variant or union type `async` in this scope
diff --git a/tests/ui/editions/edition-cstr-2015-2018.rs b/tests/ui/editions/edition-cstr-2015-2018.rs
index 4c35c48646a..4d4274251f0 100644
--- a/tests/ui/editions/edition-cstr-2015-2018.rs
+++ b/tests/ui/editions/edition-cstr-2015-2018.rs
@@ -7,7 +7,7 @@ macro_rules! contain { () => { c"str" } }
     //~| NOTE expected one of 8 possible tokens
     //~| NOTE you may be trying to write a c-string literal
     //~| NOTE c-string literals require Rust 2021 or later
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 
 fn check_macro_construct() {
@@ -29,7 +29,7 @@ fn check_basic() {
     //~| NOTE expected one of 8 possible tokens
     //~| NOTE you may be trying to write a c-string literal
     //~| NOTE c-string literals require Rust 2021 or later
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -39,7 +39,7 @@ fn check_craw() {
     //~| NOTE expected one of 8 possible tokens
     //~| NOTE you may be trying to write a c-string literal
     //~| NOTE c-string literals require Rust 2021 or later
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
@@ -49,7 +49,7 @@ fn check_craw_hash() {
     //~| NOTE expected one of 8 possible tokens
     //~| NOTE you may be trying to write a c-string literal
     //~| NOTE c-string literals require Rust 2021 or later
-    //~| HELP pass `--edition 2021` to `rustc`
+    //~| HELP pass `--edition 2024` to `rustc`
     //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
 }
 
diff --git a/tests/ui/editions/edition-cstr-2015-2018.stderr b/tests/ui/editions/edition-cstr-2015-2018.stderr
index b864df308ef..62cb8576552 100644
--- a/tests/ui/editions/edition-cstr-2015-2018.stderr
+++ b/tests/ui/editions/edition-cstr-2015-2018.stderr
@@ -6,7 +6,7 @@ LL |     c"str";
    |
    = note: you may be trying to write a c-string literal
    = note: c-string literals require Rust 2021 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
@@ -17,7 +17,7 @@ LL |     cr"str";
    |
    = note: you may be trying to write a c-string literal
    = note: c-string literals require Rust 2021 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
@@ -28,7 +28,7 @@ LL |     cr##"str"##;
    |
    = note: you may be trying to write a c-string literal
    = note: c-string literals require Rust 2021 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
@@ -59,7 +59,7 @@ LL |     contain!();
    |
    = note: you may be trying to write a c-string literal
    = note: c-string literals require Rust 2021 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
    = note: this error originates in the macro `contain` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/error-emitter/unicode-output.rs b/tests/ui/error-emitter/unicode-output.rs
index ba6db37b66c..5c083c4e575 100644
--- a/tests/ui/error-emitter/unicode-output.rs
+++ b/tests/ui/error-emitter/unicode-output.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Zunstable-options=yes --error-format=human-unicode --color=always
+//@ compile-flags: -Zunstable-options --error-format=human-unicode --color=always
 //@ edition:2018
 //@ only-linux
 
diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs
index a686357d910..f20dc56f122 100644
--- a/tests/ui/feature-gates/feature-gate-coroutines.rs
+++ b/tests/ui/feature-gates/feature-gate-coroutines.rs
@@ -1,5 +1,5 @@
 //@ revisions: e2024 none
-//@[e2024] compile-flags: --edition 2024 -Zunstable-options
+//@[e2024] edition: 2024
 
 fn main() {
     yield true; //~ ERROR yield syntax is experimental
diff --git a/tests/ui/feature-gates/feature-gate-gen_blocks.rs b/tests/ui/feature-gates/feature-gate-gen_blocks.rs
index d9bfeac36ed..01fd922b0e9 100644
--- a/tests/ui/feature-gates/feature-gate-gen_blocks.rs
+++ b/tests/ui/feature-gates/feature-gate-gen_blocks.rs
@@ -1,5 +1,5 @@
 //@ revisions: e2024 none
-//@[e2024] compile-flags: --edition 2024 -Zunstable-options
+//@[e2024] edition: 2024
 
 fn test_gen() {
     gen {};
diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs
index b33fda8e154..7fffe312f4b 100644
--- a/tests/ui/generic-associated-types/issue-71176.rs
+++ b/tests/ui/generic-associated-types/issue-71176.rs
@@ -16,6 +16,8 @@ struct Holder<B> {
 
 fn main() {
     Holder {
-        inner: Box::new(()), //~ ERROR: the trait `Provider` cannot be made into an object
+        inner: Box::new(()),
+        //~^ ERROR: the trait `Provider` cannot be made into an object
+        //~| ERROR: the trait `Provider` cannot be made into an object
     };
 }
diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr
index 15d5a3df6f2..1cd2ed0d313 100644
--- a/tests/ui/generic-associated-types/issue-71176.stderr
+++ b/tests/ui/generic-associated-types/issue-71176.stderr
@@ -80,7 +80,24 @@ LL |     type A<'a>;
    = help: consider moving `A` to another trait
    = help: only type `()` implements the trait, consider using it directly instead
 
-error: aborting due to 5 previous errors
+error[E0038]: the trait `Provider` cannot be made into an object
+  --> $DIR/issue-71176.rs:19:16
+   |
+LL |         inner: Box::new(()),
+   |                ^^^^^^^^^^^^ `Provider` 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/issue-71176.rs:2:10
+   |
+LL | trait Provider {
+   |       -------- this trait cannot be made into an object...
+LL |     type A<'a>;
+   |          ^ ...because it contains the generic associated type `A`
+   = help: consider moving `A` to another trait
+   = help: only type `()` implements the trait, consider using it directly instead
+   = note: required for the cast from `Box<()>` to `Box<(dyn Provider<A<'_> = _> + 'static), {type error}>`
+
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0038, E0107.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/generics/generics-on-self-mod-segment.rs b/tests/ui/generics/generics-on-self-mod-segment.rs
new file mode 100644
index 00000000000..ef229eeba53
--- /dev/null
+++ b/tests/ui/generics/generics-on-self-mod-segment.rs
@@ -0,0 +1,18 @@
+struct Ty;
+
+fn self_(_: self::<i32>::Ty) {}
+//~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment`
+
+fn crate_(_: crate::<i32>::Ty) {}
+//~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment`
+
+macro_rules! dollar_crate {
+    () => {
+        fn dollar_crate_(_: $crate::<i32>::Ty) {}
+        //~^ ERROR type arguments are not allowed on module `generics_on_self_mod_segment`
+    }
+}
+
+dollar_crate!();
+
+fn main() {}
diff --git a/tests/ui/generics/generics-on-self-mod-segment.stderr b/tests/ui/generics/generics-on-self-mod-segment.stderr
new file mode 100644
index 00000000000..4a2d5939a3e
--- /dev/null
+++ b/tests/ui/generics/generics-on-self-mod-segment.stderr
@@ -0,0 +1,32 @@
+error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment`
+  --> $DIR/generics-on-self-mod-segment.rs:3:20
+   |
+LL | fn self_(_: self::<i32>::Ty) {}
+   |             ----   ^^^ type argument not allowed
+   |             |
+   |             not allowed on module `generics_on_self_mod_segment`
+
+error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment`
+  --> $DIR/generics-on-self-mod-segment.rs:6:22
+   |
+LL | fn crate_(_: crate::<i32>::Ty) {}
+   |              -----   ^^^ type argument not allowed
+   |              |
+   |              not allowed on module `generics_on_self_mod_segment`
+
+error[E0109]: type arguments are not allowed on module `generics_on_self_mod_segment`
+  --> $DIR/generics-on-self-mod-segment.rs:11:38
+   |
+LL |         fn dollar_crate_(_: $crate::<i32>::Ty) {}
+   |                             ------   ^^^ type argument not allowed
+   |                             |
+   |                             not allowed on module `generics_on_self_mod_segment`
+...
+LL | dollar_crate!();
+   | --------------- in this macro invocation
+   |
+   = note: this error originates in the macro `dollar_crate` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0109`.
diff --git a/tests/ui/higher-ranked/builtin-closure-like-bounds.rs b/tests/ui/higher-ranked/builtin-closure-like-bounds.rs
index dee290cc439..c177ee6fb3a 100644
--- a/tests/ui/higher-ranked/builtin-closure-like-bounds.rs
+++ b/tests/ui/higher-ranked/builtin-closure-like-bounds.rs
@@ -1,5 +1,4 @@
 //@ edition:2024
-//@ compile-flags: -Zunstable-options
 //@ revisions: current next
 //@[next] compile-flags: -Znext-solver
 //@ check-pass
diff --git a/tests/ui/impl-trait/example-calendar.rs b/tests/ui/impl-trait/example-calendar.rs
index 1dadc5dfcb3..c3c01f01036 100644
--- a/tests/ui/impl-trait/example-calendar.rs
+++ b/tests/ui/impl-trait/example-calendar.rs
@@ -156,7 +156,7 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
 }
 
 impl std::iter::Step for NaiveDate {
-    fn steps_between(_: &Self, _: &Self) -> Option<usize> {
+    fn steps_between(_: &Self, _: &Self) -> (usize, Option<usize>) {
         unimplemented!()
     }
 
diff --git a/tests/ui/impl-trait/in-trait/late-bound-in-object-assocty.rs b/tests/ui/impl-trait/in-trait/late-bound-in-object-assocty.rs
index 83466535e13..42b33c6e31d 100644
--- a/tests/ui/impl-trait/in-trait/late-bound-in-object-assocty.rs
+++ b/tests/ui/impl-trait/in-trait/late-bound-in-object-assocty.rs
@@ -1,5 +1,5 @@
 // Test for issue #132429
-//@compile-flags: -Zunstable-options --edition=2024
+//@ edition: 2024
 //@check-pass
 
 use std::future::Future;
diff --git a/tests/ui/impl-trait/issues/issue-79099.stderr b/tests/ui/impl-trait/issues/issue-79099.stderr
index 6c26d5bd1b7..96825eabec7 100644
--- a/tests/ui/impl-trait/issues/issue-79099.stderr
+++ b/tests/ui/impl-trait/issues/issue-79099.stderr
@@ -6,7 +6,7 @@ LL |         let f: impl core::future::Future<Output = u8> = async { 1 };
    |                                                         |
    |                                                         `async` blocks are only allowed in Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
index caaac5434c5..6f0f287fe12 100644
--- a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
+++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
@@ -74,7 +74,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/opaque-used-in-extraneous-argument.rs:20:5
    |
 LL |     open_parent(&old_path)
-   |     ^^^^^^^^^^^ --------- unexpected argument of type `&impl FnOnce<{type error}, Output = {type error}> + Fn<{type error}> + 'static`
+   |     ^^^^^^^^^^^ --------- unexpected argument of type `&impl Fn<{type error}> + FnOnce<{type error}, Output = {type error}> + 'static`
    |
 note: function defined here
   --> $DIR/opaque-used-in-extraneous-argument.rs:12:4
diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs
index 49015bc48ba..09b7ef14e6b 100644
--- a/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs
+++ b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 
 use std::fmt::Display;
 
diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs
index 5ef8542d862..7b53b20ceff 100644
--- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs
+++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 
 #![feature(rustc_attrs)]
 #![feature(type_alias_impl_trait)]
diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr
index b14ed20bd36..4d8c5cb40b4 100644
--- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr
+++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr
@@ -1,5 +1,5 @@
 error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
-  --> $DIR/capturing-implicit.rs:8:11
+  --> $DIR/capturing-implicit.rs:7:11
    |
 LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
    |           ^       -------------------------------------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
@@ -7,13 +7,13 @@ LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
    |           this lifetime parameter is captured
 
 error: ['_: o]
-  --> $DIR/capturing-implicit.rs:8:19
+  --> $DIR/capturing-implicit.rs:7:19
    |
 LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: ['_: o]
-  --> $DIR/capturing-implicit.rs:8:44
+  --> $DIR/capturing-implicit.rs:7:44
    |
 LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
    |                                            ^^^^^^^^^^
diff --git a/tests/ui/impl-trait/precise-capturing/external-macro.rs b/tests/ui/impl-trait/precise-capturing/external-macro.rs
index 492e8036461..87bad7455eb 100644
--- a/tests/ui/impl-trait/precise-capturing/external-macro.rs
+++ b/tests/ui/impl-trait/precise-capturing/external-macro.rs
@@ -5,7 +5,6 @@
 //@ aux-crate: no_use_pm=no-use-pm.rs
 //@ aux-crate: no_use_macro=no-use-macro.rs
 //@ edition: 2024
-//@ compile-flags:-Z unstable-options
 //@ check-pass
 
 no_use_pm::pm_rpit!{}
diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
index 2a17ef72912..cd9ed0fb885 100644
--- a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
+++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr
@@ -16,7 +16,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has
 LL |     let h = foreign::hello(&x);
    |             ^^^^^^^^^^^^^^^^^^
 help: if you can modify this crate, add a precise capturing bound to avoid overcapturing: `+ use<>`
-  --> $DIR/auxiliary/foreign.rs:6:31
+  --> $DIR/auxiliary/foreign.rs:5:31
    |
 LL | pub fn hello(x: &Vec<i32>) -> impl Display { 0 }
    |                               ^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs
index 1d98750f6dd..36db07e5764 100644
--- a/tests/ui/impl-trait/precise-capturing/migration-note.rs
+++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 
 use std::fmt::Display;
 
diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr
index a859a114dbc..c9403532dfa 100644
--- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr
+++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/migration-note.rs:183:17
+  --> $DIR/migration-note.rs:182:17
    |
 LL |     let x = vec![0];
    |         - binding `x` declared here
@@ -14,7 +14,7 @@ LL | }
    | - `x` dropped here while still borrowed
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/migration-note.rs:20:5
+  --> $DIR/migration-note.rs:19:5
    |
 LL |     let a = display_len(&x);
    |                         -- immutable borrow occurs here
@@ -26,7 +26,7 @@ LL |     println!("{a}");
    |               --- immutable borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:17:13
+  --> $DIR/migration-note.rs:16:13
    |
 LL |     let a = display_len(&x);
    |             ^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
    |                                               ++++++++
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/migration-note.rs:30:25
+  --> $DIR/migration-note.rs:29:25
    |
 LL |     let x = vec![1];
    |         - binding `x` declared here
@@ -51,7 +51,7 @@ LL | }
    | - `x` dropped here while still borrowed
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:30:13
+  --> $DIR/migration-note.rs:29:13
    |
 LL |     let a = display_len(&x);
    |             ^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
    |                                               ++++++++
 
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/migration-note.rs:49:8
+  --> $DIR/migration-note.rs:48:8
    |
 LL |     let x = vec![1];
    |         - binding `x` declared here
@@ -76,7 +76,7 @@ LL | }
    | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display`
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:44:13
+  --> $DIR/migration-note.rs:43:13
    |
 LL |     let a = display_len(&x);
    |             ^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     let a = display_len(&x.clone());
    |                           ++++++++
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/migration-note.rs:67:5
+  --> $DIR/migration-note.rs:66:5
    |
 LL |     let a = display_len_mut(&mut x);
    |                             ------ first mutable borrow occurs here
@@ -102,7 +102,7 @@ LL |     println!("{a}");
    |               --- first borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:64:13
+  --> $DIR/migration-note.rs:63:13
    |
 LL |     let a = display_len_mut(&mut x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +112,7 @@ LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
    |                                                       ++++++++
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/migration-note.rs:77:29
+  --> $DIR/migration-note.rs:76:29
    |
 LL |     let mut x = vec![1];
    |         ----- binding `x` declared here
@@ -127,7 +127,7 @@ LL | }
    | - `x` dropped here while still borrowed
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:77:13
+  --> $DIR/migration-note.rs:76:13
    |
 LL |     let a = display_len_mut(&mut x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -137,7 +137,7 @@ LL | fn display_len_mut<T>(x: &mut Vec<T>) -> impl Display + use<T> {
    |                                                       ++++++++
 
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/migration-note.rs:96:8
+  --> $DIR/migration-note.rs:95:8
    |
 LL |     let mut x = vec![1];
    |         ----- binding `x` declared here
@@ -152,7 +152,7 @@ LL | }
    | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display`
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:91:13
+  --> $DIR/migration-note.rs:90:13
    |
 LL |     let a = display_len_mut(&mut x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@ LL |     let a = display_len_mut(&mut x.clone());
    |                                   ++++++++
 
 error[E0506]: cannot assign to `s.f` because it is borrowed
-  --> $DIR/migration-note.rs:116:5
+  --> $DIR/migration-note.rs:115:5
    |
 LL |     let a = display_field(&s.f);
    |                           ---- `s.f` is borrowed here
@@ -178,7 +178,7 @@ LL |     println!("{a}");
    |               --- borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:113:13
+  --> $DIR/migration-note.rs:112:13
    |
 LL |     let a = display_field(&s.f);
    |             ^^^^^^^^^^^^^^^^^^^
@@ -188,7 +188,7 @@ LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
    |                                                            ++++++++
 
 error[E0506]: cannot assign to `s.f` because it is borrowed
-  --> $DIR/migration-note.rs:132:5
+  --> $DIR/migration-note.rs:131:5
    |
 LL |     let a = display_field(&mut s.f);
    |                           -------- `s.f` is borrowed here
@@ -200,7 +200,7 @@ LL |     println!("{a}");
    |               --- borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:129:13
+  --> $DIR/migration-note.rs:128:13
    |
 LL |     let a = display_field(&mut s.f);
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -210,7 +210,7 @@ LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
    |                                                            ++++++++
 
 error[E0503]: cannot use `s.f` because it was mutably borrowed
-  --> $DIR/migration-note.rs:144:5
+  --> $DIR/migration-note.rs:143:5
    |
 LL |     let a = display_field(&mut s.f);
    |                           -------- `s.f` is borrowed here
@@ -222,7 +222,7 @@ LL |     println!("{a}");
    |               --- borrow later used here
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:141:13
+  --> $DIR/migration-note.rs:140:13
    |
 LL |     let a = display_field(&mut s.f);
    |             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -232,7 +232,7 @@ LL | fn display_field<T: Copy + Display>(t: &T) -> impl Display + use<T> {
    |                                                            ++++++++
 
 error[E0597]: `z.f` does not live long enough
-  --> $DIR/migration-note.rs:160:25
+  --> $DIR/migration-note.rs:159:25
    |
 LL |         let z = Z { f: vec![1] };
    |             - binding `z` declared here
@@ -248,7 +248,7 @@ LL | }
    |
    = note: values in a scope are dropped in the opposite order they are defined
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:160:13
+  --> $DIR/migration-note.rs:159:13
    |
 LL |         x = display_len(&z.f);
    |             ^^^^^^^^^^^^^^^^^
@@ -258,7 +258,7 @@ LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
    |                                               ++++++++
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/migration-note.rs:171:40
+  --> $DIR/migration-note.rs:170:40
    |
 LL |     let x = { let x = display_len(&mut vec![0]); x };
    |                                        ^^^^^^^ - - borrow later used here
@@ -268,7 +268,7 @@ LL |     let x = { let x = display_len(&mut vec![0]); x };
    |
    = note: consider using a `let` binding to create a longer lived value
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:171:23
+  --> $DIR/migration-note.rs:170:23
    |
 LL |     let x = { let x = display_len(&mut vec![0]); x };
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +279,7 @@ LL | fn display_len<T>(x: &Vec<T>) -> impl Display + use<T> {
    |                                               ++++++++
 
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/migration-note.rs:199:10
+  --> $DIR/migration-note.rs:198:10
    |
 LL |     let x = String::new();
    |         - binding `x` declared here
@@ -294,12 +294,12 @@ LL | }
    | - borrow might be used here, when `y` is dropped and runs the destructor for type `impl Sized`
    |
 note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
-  --> $DIR/migration-note.rs:196:13
+  --> $DIR/migration-note.rs:195:13
    |
 LL |     let y = capture_apit(&x);
    |             ^^^^^^^^^^^^^^^^
 note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
-  --> $DIR/migration-note.rs:190:21
+  --> $DIR/migration-note.rs:189:21
    |
 LL | fn capture_apit(x: &impl Sized) -> impl Sized {}
    |                     ^^^^^^^^^^
diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs
index e19d935f5b0..075d7c70ac6 100644
--- a/tests/ui/impl-trait/precise-capturing/redundant.rs
+++ b/tests/ui/impl-trait/precise-capturing/redundant.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Zunstable-options --edition=2024
+//@ edition: 2024
 //@ check-pass
 
 #![feature(precise_capturing_in_traits)]
diff --git a/tests/ui/inline-const/const_block_pat_liveness.rs b/tests/ui/inline-const/const-block-pat-liveness.rs
index 26393a4f65b..26393a4f65b 100644
--- a/tests/ui/inline-const/const_block_pat_liveness.rs
+++ b/tests/ui/inline-const/const-block-pat-liveness.rs
diff --git a/tests/ui/inline-const/cross_const_control_flow.rs b/tests/ui/inline-const/cross-const-control-flow-125846.rs
index 109764a1812..109764a1812 100644
--- a/tests/ui/inline-const/cross_const_control_flow.rs
+++ b/tests/ui/inline-const/cross-const-control-flow-125846.rs
diff --git a/tests/ui/inline-const/cross_const_control_flow.stderr b/tests/ui/inline-const/cross-const-control-flow-125846.stderr
index ecfa921edd2..4aa1c273504 100644
--- a/tests/ui/inline-const/cross_const_control_flow.stderr
+++ b/tests/ui/inline-const/cross-const-control-flow-125846.stderr
@@ -1,5 +1,5 @@
 error[E0767]: use of unreachable label `'a`
-  --> $DIR/cross_const_control_flow.rs:9:25
+  --> $DIR/cross-const-control-flow-125846.rs:9:25
    |
 LL |     'a: { const { break 'a } }
    |     --                  ^^ unreachable label `'a`
@@ -9,7 +9,7 @@ LL |     'a: { const { break 'a } }
    = note: labels are unreachable through functions, closures, async blocks and modules
 
 error[E0767]: use of unreachable label `'a`
-  --> $DIR/cross_const_control_flow.rs:22:28
+  --> $DIR/cross-const-control-flow-125846.rs:22:28
    |
 LL |     'a: { const { continue 'a } }
    |     --                     ^^ unreachable label `'a`
@@ -19,7 +19,7 @@ LL |     'a: { const { continue 'a } }
    = note: labels are unreachable through functions, closures, async blocks and modules
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/cross_const_control_flow.rs:41:14
+  --> $DIR/cross-const-control-flow-125846.rs:41:14
    |
 LL |     const { &x };
    |              ^ non-constant value
@@ -30,7 +30,7 @@ LL |     const x: /* Type */ = 1;
    |     ~~~~~  ++++++++++++
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/cross_const_control_flow.rs:35:22
+  --> $DIR/cross-const-control-flow-125846.rs:35:22
    |
 LL |     const { async {}.await }
    |           -----------^^^^^--
@@ -39,31 +39,31 @@ LL |     const { async {}.await }
    |           this is not `async`
 
 error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/cross_const_control_flow.rs:9:19
+  --> $DIR/cross-const-control-flow-125846.rs:9:19
    |
 LL |     'a: { const { break 'a } }
    |                   ^^^^^^^^ cannot `break` outside of a loop or labeled block
 
 error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/cross_const_control_flow.rs:16:17
+  --> $DIR/cross-const-control-flow-125846.rs:16:17
    |
 LL |         const { break }
    |                 ^^^^^ cannot `break` outside of a loop or labeled block
 
 error[E0268]: `continue` outside of a loop
-  --> $DIR/cross_const_control_flow.rs:22:19
+  --> $DIR/cross-const-control-flow-125846.rs:22:19
    |
 LL |     'a: { const { continue 'a } }
    |                   ^^^^^^^^^^^ cannot `continue` outside of a loop
 
 error[E0268]: `continue` outside of a loop
-  --> $DIR/cross_const_control_flow.rs:29:17
+  --> $DIR/cross-const-control-flow-125846.rs:29:17
    |
 LL |         const { continue }
    |                 ^^^^^^^^ cannot `continue` outside of a loop
 
 error[E0572]: return statement outside of function body
-  --> $DIR/cross_const_control_flow.rs:4:13
+  --> $DIR/cross-const-control-flow-125846.rs:4:13
    |
 LL | / fn foo() {
 LL | |     const { return }
diff --git a/tests/ui/inline-const/referencing_local_variables.rs b/tests/ui/inline-const/referencing-local-variables.rs
index f9f0fef07f0..f9f0fef07f0 100644
--- a/tests/ui/inline-const/referencing_local_variables.rs
+++ b/tests/ui/inline-const/referencing-local-variables.rs
diff --git a/tests/ui/inline-const/referencing_local_variables.stderr b/tests/ui/inline-const/referencing-local-variables.stderr
index 4a0a5406602..7e1cecdddcb 100644
--- a/tests/ui/inline-const/referencing_local_variables.stderr
+++ b/tests/ui/inline-const/referencing-local-variables.stderr
@@ -1,5 +1,5 @@
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/referencing_local_variables.rs:2:13
+  --> $DIR/referencing-local-variables.rs:2:13
    |
 LL | const fn test_me<T>(a: usize) -> usize {
    |                     - this would need to be a `const`
diff --git a/tests/ui/inline-const/uninit_local.rs b/tests/ui/inline-const/uninit-local.rs
index 548c053affc..548c053affc 100644
--- a/tests/ui/inline-const/uninit_local.rs
+++ b/tests/ui/inline-const/uninit-local.rs
diff --git a/tests/ui/inline-const/uninit_local.stderr b/tests/ui/inline-const/uninit-local.stderr
index 37b78e337e7..fab65ffb5fa 100644
--- a/tests/ui/inline-const/uninit_local.stderr
+++ b/tests/ui/inline-const/uninit-local.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/uninit_local.rs:4:15
+  --> $DIR/uninit-local.rs:4:15
    |
 LL |         let x: bool;
    |             - binding declared here but left uninitialized
diff --git a/tests/ui/issues/issue-48006.rs b/tests/ui/issues/issue-48006.rs
index e48146d07bc..1adc76f2a26 100644
--- a/tests/ui/issues/issue-48006.rs
+++ b/tests/ui/issues/issue-48006.rs
@@ -6,10 +6,10 @@ use std::iter::Step;
 
 #[cfg(target_pointer_width = "16")]
 fn main() {
-    assert!(Step::steps_between(&0u32, &u32::MAX).is_none());
+    assert!(Step::steps_between(&0u32, &u32::MAX).1.is_none());
 }
 
 #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
 fn main() {
-    assert!(Step::steps_between(&0u32, &u32::MAX).is_some());
+    assert!(Step::steps_between(&0u32, &u32::MAX).1.is_some());
 }
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs
index ffd6f022bc6..6e9b38be080 100644
--- a/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs
@@ -1,6 +1,5 @@
 //@ check-pass
 //@ edition:2024
-//@ compile-flags: -Zunstable-options
 
 use std::ops::Deref;
 use std::rc::Rc;
diff --git a/tests/ui/layout/ice-type-error-in-tail-124031.rs b/tests/ui/layout/ice-type-error-in-tail-124031.rs
index 0a2be117403..ecd6f3d56f3 100644
--- a/tests/ui/layout/ice-type-error-in-tail-124031.rs
+++ b/tests/ui/layout/ice-type-error-in-tail-124031.rs
@@ -1,3 +1,5 @@
+//@ normalize-stderr-test: "\d+ bits" -> "$$BITS bits"
+
 // Regression test for issue #124031
 // Checks that we don't ICE when the tail
 // of an ADT has a type error
@@ -16,5 +18,6 @@ struct Other {
 fn main() {
     unsafe {
         std::mem::transmute::<Option<()>, Option<&Other>>(None);
+        //~^ ERROR cannot transmute between types of different sizes
     }
 }
diff --git a/tests/ui/layout/ice-type-error-in-tail-124031.stderr b/tests/ui/layout/ice-type-error-in-tail-124031.stderr
index 57dc83f92df..a066e8574dc 100644
--- a/tests/ui/layout/ice-type-error-in-tail-124031.stderr
+++ b/tests/ui/layout/ice-type-error-in-tail-124031.stderr
@@ -1,5 +1,5 @@
 error[E0046]: not all trait items implemented, missing: `RefTarget`
-  --> $DIR/ice-type-error-in-tail-124031.rs:9:1
+  --> $DIR/ice-type-error-in-tail-124031.rs:11:1
    |
 LL |     type RefTarget;
    |     -------------- `RefTarget` from trait
@@ -7,6 +7,16 @@ LL |     type RefTarget;
 LL | impl Trait for () {}
    | ^^^^^^^^^^^^^^^^^ missing `RefTarget` in implementation
 
-error: aborting due to 1 previous error
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/ice-type-error-in-tail-124031.rs:20:9
+   |
+LL |         std::mem::transmute::<Option<()>, Option<&Other>>(None);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<()>` ($BITS bits)
+   = note: target type: `Option<&Other>` ($BITS bits)
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0046`.
+Some errors have detailed explanations: E0046, E0512.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs b/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs
new file mode 100644
index 00000000000..6ded9118700
--- /dev/null
+++ b/tests/ui/lazy-type-alias/bad-lazy-type-alias.rs
@@ -0,0 +1,18 @@
+// regression test for #127351
+
+#![feature(lazy_type_alias)]
+//~^ WARN the feature `lazy_type_alias` is incomplete
+
+type ExplicitTypeOutlives<T> = T;
+
+pub struct Warns {
+    _significant_drop: ExplicitTypeOutlives,
+    //~^ ERROR missing generics for type alias `ExplicitTypeOutlives`
+    field: String,
+}
+
+pub fn test(w: Warns) {
+    let _ = || drop(w.field);
+}
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr b/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr
new file mode 100644
index 00000000000..3a5ded60241
--- /dev/null
+++ b/tests/ui/lazy-type-alias/bad-lazy-type-alias.stderr
@@ -0,0 +1,28 @@
+warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/bad-lazy-type-alias.rs:3:12
+   |
+LL | #![feature(lazy_type_alias)]
+   |            ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0107]: missing generics for type alias `ExplicitTypeOutlives`
+  --> $DIR/bad-lazy-type-alias.rs:9:24
+   |
+LL |     _significant_drop: ExplicitTypeOutlives,
+   |                        ^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
+   |
+note: type alias defined here, with 1 generic parameter: `T`
+  --> $DIR/bad-lazy-type-alias.rs:6:6
+   |
+LL | type ExplicitTypeOutlives<T> = T;
+   |      ^^^^^^^^^^^^^^^^^^^^ -
+help: add missing generic argument
+   |
+LL |     _significant_drop: ExplicitTypeOutlives<T>,
+   |                                            +++
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
index 2ac97aff2b0..741cdacdb1d 100644
--- a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
+++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 
 fn main() {
     let _ = { String::new().as_str() }.len();
diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
index 96e88eaca92..6770da091ce 100644
--- a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
+++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/tail-expr-in-nested-expr.rs:5:15
+  --> $DIR/tail-expr-in-nested-expr.rs:4:15
    |
 LL |     let _ = { String::new().as_str() }.len();
    |               ^^^^^^^^^^^^^---------
diff --git a/tests/ui/macros/expr_2021_implicit_in_2024.rs b/tests/ui/macros/expr_2021_implicit_in_2024.rs
index b3f7a31a802..f2eee1aa272 100644
--- a/tests/ui/macros/expr_2021_implicit_in_2024.rs
+++ b/tests/ui/macros/expr_2021_implicit_in_2024.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: --edition=2024 -Zunstable-options
+//@ edition: 2024
 //@ aux-build:expr_2021_implicit.rs
 
 //@ check-pass
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
index 312256f1879..257f5b2f8cf 100644
--- a/tests/ui/macros/expr_2021_inline_const.rs
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -1,6 +1,6 @@
 //@ revisions: edi2021 edi2024
-//@[edi2024]compile-flags: --edition=2024 -Z unstable-options
-//@[edi2021]compile-flags: --edition=2021
+//@[edi2024] edition: 2024
+//@[edi2021] edition: 2021
 
 // This test ensures that the inline const match only on edition 2024
 macro_rules! m2021 {
diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs
index 6f8ec139109..1d45d60c136 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.rs
+++ b/tests/ui/macros/expr_2024_underscore_expr.rs
@@ -1,6 +1,6 @@
 //@ revisions: edi2021 edi2024
-//@[edi2024]compile-flags: --edition=2024 -Z unstable-options
-//@[edi2021]compile-flags: --edition=2021
+//@[edi2024] edition: 2024
+//@[edi2021] edition: 2021
 // This test ensures that the `_` tok is considered an
 // expression on edition 2024.
 macro_rules! m2021 {
diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
index 9a5b92f5032..ae1bc00236f 100644
--- a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
+++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: --edition=2024 -Z unstable-options
+//@ edition: 2024
 //@ aux-build: metavar_2018.rs
 //@ known-bug: #130484
 //@ run-pass
diff --git a/tests/ui/match/intended-binding-pattern-is-const.rs b/tests/ui/match/intended-binding-pattern-is-const.rs
new file mode 100644
index 00000000000..95c8119cdb9
--- /dev/null
+++ b/tests/ui/match/intended-binding-pattern-is-const.rs
@@ -0,0 +1,10 @@
+fn main() {
+    match 1 { //~ ERROR non-exhaustive patterns
+        //~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+        //~| the matched value is of type `i32`
+        x => {} //~ this pattern doesn't introduce a new catch-all binding
+        //~^ HELP ensure that all possible cases are being handled
+        //~| HELP if you meant to introduce a binding, use a different name
+    }
+    const x: i32 = 4; //~ NOTE constant `x` defined here
+}
diff --git a/tests/ui/match/intended-binding-pattern-is-const.stderr b/tests/ui/match/intended-binding-pattern-is-const.stderr
new file mode 100644
index 00000000000..99af1c7a16e
--- /dev/null
+++ b/tests/ui/match/intended-binding-pattern-is-const.stderr
@@ -0,0 +1,27 @@
+error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+  --> $DIR/intended-binding-pattern-is-const.rs:2:11
+   |
+LL |     match 1 {
+   |           ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+...
+LL |         x => {}
+   |         - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x`
+   |
+   = note: the matched value is of type `i32`
+note: constant `x` defined here
+  --> $DIR/intended-binding-pattern-is-const.rs:9:5
+   |
+LL |     const x: i32 = 4;
+   |     ^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         x_var => {}
+   |          ++++
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL |         x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!()
+   |                ++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
index 7cbe8e0943a..bc12d69b105 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 // gate-test-ref_pat_eat_one_layer_2024_structural
 
 pub fn main() {
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
index b3ea60252ac..132fe421a18 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:6:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:5:22
    |
 LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
    |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -14,7 +14,7 @@ LL |     if let Some(Some(x)) = &Some(&Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:11:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:10:23
    |
 LL |         let _: &u32 = x;
    |                ----   ^ expected `&u32`, found integer
@@ -27,7 +27,7 @@ LL |         let _: &u32 = &x;
    |                       +
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:14:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:13:23
    |
 LL |     if let Some(Some(&&x)) = &Some(Some(&0)) {
    |                       ^^     --------------- this expression has type `&Option<Option<&{integer}>>`
@@ -43,7 +43,7 @@ LL +     if let Some(Some(&x)) = &Some(Some(&0)) {
    |
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:18:17
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:17:17
    |
 LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -54,7 +54,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
            found reference `&_`
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
@@ -64,7 +64,7 @@ LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:22:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^
@@ -74,7 +74,7 @@ LL |     if let Some(Some(x)) = &mut Some(&mut Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:26:22
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:25:22
    |
 LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
    |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -89,7 +89,7 @@ LL |     if let Some(Some(x)) = &Some(&Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:30:27
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:29:27
    |
 LL |     if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
    |                           ^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
@@ -104,7 +104,7 @@ LL |     if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
    |                           ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
    |
 LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
@@ -114,7 +114,7 @@ LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:34:23
+  --> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
    |
 LL |     if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
    |                       ^^^^^^
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
index c6a699d2ff8..b145446de0a 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
@@ -1,6 +1,5 @@
 //@ run-pass
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ revisions: classic structural both
 #![allow(incomplete_features)]
 #![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr
index 0215df98ea1..f8672d755b9 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17
    |
 LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
    |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -10,7 +10,7 @@ LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:12:23
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11:23
    |
 LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
@@ -21,7 +21,7 @@ LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:16:27
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27
    |
 LL |         let _: &mut u32 = x;
    |                --------   ^ types differ in mutability
@@ -32,7 +32,7 @@ LL |         let _: &mut u32 = x;
                       found reference `&{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19:23
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18:23
    |
 LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
@@ -43,7 +43,7 @@ LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:22:29
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:29
    |
 LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
    |                             ^^^^^^       ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
@@ -54,7 +54,7 @@ LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -65,7 +65,7 @@ LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -76,7 +76,7 @@ LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
    |
 LL |     let &mut _ = &&0;
    |         ^^^^^^   --- this expression has type `&&{integer}`
@@ -87,7 +87,7 @@ LL |     let &mut _ = &&0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
    |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
@@ -98,7 +98,7 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:9
    |
 LL |     let &mut _ = &&mut 0;
    |         ^^^^^^   ------- this expression has type `&&mut {integer}`
@@ -109,7 +109,7 @@ LL |     let &mut _ = &&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:48:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
    |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
@@ -120,7 +120,7 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:51:14
    |
 LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
    |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
@@ -131,7 +131,7 @@ LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
            found mutable reference `&mut _`
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:60:13
    |
 LL |     let Foo(mut a) = &Foo(0);
    |             ^^^^
@@ -141,7 +141,7 @@ LL |     let Foo(mut a) = &Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:65:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:64:13
    |
 LL |     let Foo(mut a) = &mut Foo(0);
    |             ^^^^
@@ -151,14 +151,14 @@ LL |     let Foo(mut a) = &mut Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0277]: the trait bound `&_: main::Ref` is not satisfied
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:83:14
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14
    |
 LL |     let &_ = generic();
    |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
    |
    = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
 note: required by a bound in `generic`
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:69:19
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19
    |
 LL |     fn generic<R: Ref>() -> R {
    |                   ^^^ required by this bound in `generic`
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr
index 9428b32c4af..a37316b3097 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17
    |
 LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
    |                 ^^^^^
@@ -11,7 +11,7 @@ LL |     if let Some(&Some(&_)) = &Some(&Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:12:23
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11:23
    |
 LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
    |                       ^^^^^
@@ -23,7 +23,7 @@ LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
    |                       ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:16:27
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27
    |
 LL |         let _: &mut u32 = x;
    |                --------   ^ types differ in mutability
@@ -34,7 +34,7 @@ LL |         let _: &mut u32 = x;
                       found reference `&{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19:23
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18:23
    |
 LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
    |                       ^^^^^
@@ -46,7 +46,7 @@ LL |     if let Some(&Some(&_)) = &mut Some(&Some(0)) {
    |                       ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:22:29
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:29
    |
 LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
    |                             ^^^^^
@@ -58,7 +58,7 @@ LL |     if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) {
    |                             ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^
@@ -70,7 +70,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^
@@ -82,7 +82,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
    |
 LL |     let &mut _ = &&0;
    |         ^^^^^^   --- this expression has type `&&{integer}`
@@ -93,7 +93,7 @@ LL |     let &mut _ = &&0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
    |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
@@ -104,7 +104,7 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:38:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:37:17
    |
 LL |     if let Some(&mut Some(&_)) = &Some(&mut Some(0)) {
    |                 ^^^^^
@@ -116,7 +116,7 @@ LL |     if let Some(&Some(&_)) = &Some(&mut Some(0)) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:42:22
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:41:22
    |
 LL |     if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
    |                      ^^^^^
@@ -128,7 +128,7 @@ LL |     if let Some(Some(&x)) = &Some(Some(&mut 0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:9
    |
 LL |     let &mut _ = &&mut 0;
    |         ^^^^^^   ------- this expression has type `&&mut {integer}`
@@ -139,7 +139,7 @@ LL |     let &mut _ = &&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:48:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
    |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
@@ -150,7 +150,7 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:51:14
    |
 LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
    |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
@@ -161,7 +161,7 @@ LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
            found mutable reference `&mut _`
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:60:13
    |
 LL |     let Foo(mut a) = &Foo(0);
    |             ^^^^
@@ -171,7 +171,7 @@ LL |     let Foo(mut a) = &Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:65:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:64:13
    |
 LL |     let Foo(mut a) = &mut Foo(0);
    |             ^^^^
@@ -181,14 +181,14 @@ LL |     let Foo(mut a) = &mut Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0277]: the trait bound `&_: main::Ref` is not satisfied
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:83:14
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14
    |
 LL |     let &_ = generic();
    |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
    |
    = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
 note: required by a bound in `generic`
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:69:19
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19
    |
 LL |     fn generic<R: Ref>() -> R {
    |                   ^^^ required by this bound in `generic`
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
index d23e9c8083d..fd616807b28 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ revisions: classic structural both
 #![allow(incomplete_features)]
 #![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))]
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr
index 56dad605030..2f62e9974fa 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:9:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17
    |
 LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
    |                 ^^^^^^^^^^^^^    --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -10,7 +10,7 @@ LL |     if let Some(&mut Some(&_)) = &Some(&Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:12:23
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11:23
    |
 LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&Option<&mut Option<{integer}>>`
@@ -21,7 +21,7 @@ LL |     if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:16:27
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27
    |
 LL |         let _: &mut u32 = x;
    |                --------   ^ types differ in mutability
@@ -32,7 +32,7 @@ LL |         let _: &mut u32 = x;
                       found reference `&{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:19:23
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18:23
    |
 LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
@@ -43,7 +43,7 @@ LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:22:29
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:29
    |
 LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
    |                             ^^^^^^       ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
@@ -54,7 +54,7 @@ LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:25:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -65,7 +65,7 @@ LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27:17
    |
 LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -76,7 +76,7 @@ LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
    |
 LL |     let &mut _ = &&0;
    |         ^^^^^^   --- this expression has type `&&{integer}`
@@ -87,7 +87,7 @@ LL |     let &mut _ = &&0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:35:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
    |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
@@ -98,7 +98,7 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:46:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:9
    |
 LL |     let &mut _ = &&mut 0;
    |         ^^^^^^   ------- this expression has type `&&mut {integer}`
@@ -109,7 +109,7 @@ LL |     let &mut _ = &&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:49:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:48:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
    |         ^^^^^^   --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}`
@@ -120,7 +120,7 @@ LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:52:14
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:51:14
    |
 LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
    |              ^^^^^^^^^^^^^^^^   -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}`
@@ -131,7 +131,7 @@ LL |     let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0;
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:55:17
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:54:17
    |
 LL |     if let Some(&mut _) = &mut Some(&0) {
    |                 ^^^^^^    ------------- this expression has type `&mut Option<&{integer}>`
@@ -142,7 +142,7 @@ LL |     if let Some(&mut _) = &mut Some(&0) {
            found mutable reference `&mut _`
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:61:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:60:13
    |
 LL |     let Foo(mut a) = &Foo(0);
    |             ^^^^
@@ -152,7 +152,7 @@ LL |     let Foo(mut a) = &Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: binding cannot be both mutable and by-reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:65:13
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:64:13
    |
 LL |     let Foo(mut a) = &mut Foo(0);
    |             ^^^^
@@ -162,14 +162,14 @@ LL |     let Foo(mut a) = &mut Foo(0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0277]: the trait bound `&_: main::Ref` is not satisfied
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:83:14
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14
    |
 LL |     let &_ = generic();
    |              ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_`
    |
    = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]`
 note: required by a bound in `generic`
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:69:19
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19
    |
 LL |     fn generic<R: Ref>() -> R {
    |                   ^^^ required by this bound in `generic`
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs
index 3cdf47c1dbf..79403b19365 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 #![allow(incomplete_features)]
 #![feature(ref_pat_eat_one_layer_2024)]
 
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr
index 8b86fa65c4d..52f4c09e5c0 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of a shared reference
-  --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:7:29
+  --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:6:29
    |
 LL |     if let Some(&Some(x)) = Some(&Some(&mut 0)) {
    |                       -     ^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL |     if let Some(&Some(ref x)) = Some(&Some(&mut 0)) {
    |                       +++
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:12:10
+  --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:11:10
    |
 LL |     let &ref mut x = &0;
    |          ^^^^^^^^^ cannot borrow as mutable
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed
index bc7a58a382d..e69d169966b 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ run-rustfix
 #![allow(incomplete_features)]
 #![feature(ref_pat_eat_one_layer_2024)]
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs
index c6d72b0a9d7..a300cbcd4df 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ run-rustfix
 #![allow(incomplete_features)]
 #![feature(ref_pat_eat_one_layer_2024)]
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr
index 964e9f36596..8e135b65253 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:8:31
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:7:31
    |
 LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 -             ^
@@ -7,7 +7,7 @@ LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
    |                 help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:13:31
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:12:31
    |
 LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            -                  ^
@@ -15,7 +15,7 @@ LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
    |            help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:21:15
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:20:15
    |
 LL |     let &pat!(x) = &mut 0;
    |         -     ^
@@ -23,7 +23,7 @@ LL |     let &pat!(x) = &mut 0;
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:19
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:24:19
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -         ^
@@ -31,7 +31,7 @@ LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         help: replace this `&` with `&mut`: `&mut`
 
 error[E0596]: cannot borrow as mutable inside an `&` pattern
-  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:30
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:24:30
    |
 LL |     let &(ref mut a, ref mut b) = &mut (true, false);
    |         -                    ^
diff --git a/tests/ui/mir/issue-112269.stderr b/tests/ui/mir/issue-112269.stderr
index f5b79602797..adb662c98a7 100644
--- a/tests/ui/mir/issue-112269.stderr
+++ b/tests/ui/mir/issue-112269.stderr
@@ -1,30 +1,34 @@
 error[E0005]: refutable pattern in local binding
   --> $DIR/issue-112269.rs:3:9
    |
+LL |     const x: i32 = 4;
+   |     ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
 LL |     let x: i32 = 3;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `x_var`
+   |         ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let x_var: i32 = 3;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/issue-112269.rs:7:9
    |
+LL |     const y: i32 = 3;
+   |     ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
 LL |     let y = 4;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `y_var`
+   |         ^ patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let y_var = 4;
+   |         ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/user-annotations/region-error-ice-109072.rs b/tests/ui/nll/user-annotations/region-error-ice-109072.rs
index bcdc6651cf5..3f2ad3ccbf5 100644
--- a/tests/ui/nll/user-annotations/region-error-ice-109072.rs
+++ b/tests/ui/nll/user-annotations/region-error-ice-109072.rs
@@ -11,5 +11,4 @@ impl Lt<'missing> for () { //~ ERROR undeclared lifetime
 
 fn main() {
     let _: <() as Lt<'_>>::T = &();
-    //~^ ERROR the trait bound `(): Lt<'_>` is not satisfied
 }
diff --git a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr
index c187c17d98c..d90971bed25 100644
--- a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr
+++ b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr
@@ -21,13 +21,6 @@ help: consider introducing lifetime `'missing` here
 LL | impl<'missing> Lt<'missing> for () {
    |     ++++++++++
 
-error[E0277]: the trait bound `(): Lt<'_>` is not satisfied
-  --> $DIR/region-error-ice-109072.rs:13:13
-   |
-LL |     let _: <() as Lt<'_>>::T = &();
-   |             ^^ the trait `Lt<'_>` is not implemented for `()`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0261, E0277.
-For more information about an error, try `rustc --explain E0261`.
+For more information about this error, try `rustc --explain E0261`.
diff --git a/tests/ui/parser/help-set-edition-ice-122130.stderr b/tests/ui/parser/help-set-edition-ice-122130.stderr
index fe4d212f2db..700b1ec911b 100644
--- a/tests/ui/parser/help-set-edition-ice-122130.stderr
+++ b/tests/ui/parser/help-set-edition-ice-122130.stderr
@@ -6,7 +6,7 @@ LL |     s#[c"owned_box"]
    |
    = note: you may be trying to write a c-string literal
    = note: c-string literals require Rust 2021 or later
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error: expected item, found `"owned_box"`
diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024.rs b/tests/ui/pattern/mut_preserve_binding_mode_2024.rs
index 19aa73573b4..a4afcb2e511 100644
--- a/tests/ui/pattern/mut_preserve_binding_mode_2024.rs
+++ b/tests/ui/pattern/mut_preserve_binding_mode_2024.rs
@@ -1,6 +1,5 @@
 //@ run-pass
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 #![feature(mut_ref, ref_pat_eat_one_layer_2024)]
 #![allow(incomplete_features, unused)]
 
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs
index 0b70e4404ab..daa9b7368fd 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Z unstable-options
 
 // This contains a binding in edition 2024, so if matched with a reference binding mode it will end
 // up with a `mut ref mut` binding mode. We use this to test the migration lint on patterns with
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs
index a822c90ab6e..50b716a1111 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs
@@ -1,6 +1,5 @@
 //@ check-fail
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 #![deny(rust_2024_incompatible_pat)]
 
 fn main() {}
diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr
index 33e4f0021b7..92058095f84 100644
--- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr
+++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/min_match_ergonomics_fail.rs:24:20
+  --> $DIR/min_match_ergonomics_fail.rs:23:20
    |
 LL | test_pat_on_type![(&x,): &(T,)];
    |                    ^^    ----- expected due to this
@@ -15,7 +15,7 @@ LL + test_pat_on_type![(x,): &(T,)];
    |
 
 error[E0308]: mismatched types
-  --> $DIR/min_match_ergonomics_fail.rs:26:20
+  --> $DIR/min_match_ergonomics_fail.rs:25:20
    |
 LL | test_pat_on_type![(&x,): &(&mut T,)];
    |                    ^^    ---------- expected due to this
@@ -31,7 +31,7 @@ LL + test_pat_on_type![(x,): &(&mut T,)];
    |
 
 error[E0308]: mismatched types
-  --> $DIR/min_match_ergonomics_fail.rs:27:20
+  --> $DIR/min_match_ergonomics_fail.rs:26:20
    |
 LL | test_pat_on_type![(&mut x,): &(&T,)];
    |                    ^^^^^^    ------ expected due to this
@@ -41,7 +41,7 @@ LL | test_pat_on_type![(&mut x,): &(&T,)];
    = note:      expected reference `&T`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/min_match_ergonomics_fail.rs:27:20
+  --> $DIR/min_match_ergonomics_fail.rs:26:20
    |
 LL | test_pat_on_type![(&mut x,): &(&T,)];
    |                    ^^^^^^
@@ -52,7 +52,7 @@ LL + test_pat_on_type![(x,): &(&T,)];
    |
 
 error[E0308]: mismatched types
-  --> $DIR/min_match_ergonomics_fail.rs:29:20
+  --> $DIR/min_match_ergonomics_fail.rs:28:20
    |
 LL | test_pat_on_type![(&x,): &&mut &(T,)];
    |                    ^^    ----------- expected due to this
@@ -68,7 +68,7 @@ LL + test_pat_on_type![(x,): &&mut &(T,)];
    |
 
 error[E0308]: mismatched types
-  --> $DIR/min_match_ergonomics_fail.rs:30:29
+  --> $DIR/min_match_ergonomics_fail.rs:29:29
    |
 LL | test_pat_on_type![Foo { f: (&x,) }: Foo];
    |                             ^^      --- expected due to this
@@ -84,7 +84,7 @@ LL + test_pat_on_type![Foo { f: (x,) }: Foo];
    |
 
 error[E0308]: mismatched types
-  --> $DIR/min_match_ergonomics_fail.rs:31:29
+  --> $DIR/min_match_ergonomics_fail.rs:30:29
    |
 LL | test_pat_on_type![Foo { f: (&x,) }: &mut Foo];
    |                             ^^      -------- expected due to this
@@ -100,7 +100,7 @@ LL + test_pat_on_type![Foo { f: (x,) }: &mut Foo];
    |
 
 error: patterns are not allowed to reset the default binding mode in edition 2024
-  --> $DIR/min_match_ergonomics_fail.rs:25:19
+  --> $DIR/min_match_ergonomics_fail.rs:24:19
    |
 LL | test_pat_on_type![(&x,): &(&T,)];
    |                   -^^^^
@@ -108,7 +108,7 @@ LL | test_pat_on_type![(&x,): &(&T,)];
    |                   help: desugar the match ergonomics: `&`
 
 error: patterns are not allowed to reset the default binding mode in edition 2024
-  --> $DIR/min_match_ergonomics_fail.rs:28:19
+  --> $DIR/min_match_ergonomics_fail.rs:27:19
    |
 LL | test_pat_on_type![(&mut x,): &(&mut T,)];
    |                   -^^^^^^^^
@@ -116,7 +116,7 @@ LL | test_pat_on_type![(&mut x,): &(&mut T,)];
    |                   help: desugar the match ergonomics: `&`
 
 error: patterns are not allowed to reset the default binding mode in edition 2024
-  --> $DIR/min_match_ergonomics_fail.rs:32:19
+  --> $DIR/min_match_ergonomics_fail.rs:31:19
    |
 LL | test_pat_on_type![Foo { f: &(x,) }: &Foo];
    |                   -^^^^^^^^^^^^^^^
@@ -124,7 +124,7 @@ LL | test_pat_on_type![Foo { f: &(x,) }: &Foo];
    |                   help: desugar the match ergonomics: `&`
 
 error: patterns are not allowed to reset the default binding mode in edition 2024
-  --> $DIR/min_match_ergonomics_fail.rs:33:19
+  --> $DIR/min_match_ergonomics_fail.rs:32:19
    |
 LL | test_pat_on_type![(mut x,): &(T,)];
    |                   -^^^^^^^
@@ -132,7 +132,7 @@ LL | test_pat_on_type![(mut x,): &(T,)];
    |                   help: desugar the match ergonomics: `&`
 
 error: patterns are not allowed to reset the default binding mode in edition 2024
-  --> $DIR/min_match_ergonomics_fail.rs:34:19
+  --> $DIR/min_match_ergonomics_fail.rs:33:19
    |
 LL | test_pat_on_type![(ref x,): &(T,)];
    |                   -^^^^^^^
@@ -140,7 +140,7 @@ LL | test_pat_on_type![(ref x,): &(T,)];
    |                   help: desugar the match ergonomics: `&`
 
 error: patterns are not allowed to reset the default binding mode in edition 2024
-  --> $DIR/min_match_ergonomics_fail.rs:35:19
+  --> $DIR/min_match_ergonomics_fail.rs:34:19
    |
 LL | test_pat_on_type![(ref mut x,): &mut (T,)];
    |                   -^^^^^^^^^^^
@@ -148,7 +148,7 @@ LL | test_pat_on_type![(ref mut x,): &mut (T,)];
    |                   help: desugar the match ergonomics: `&mut`
 
 error: patterns are not allowed to reset the default binding mode in edition 2024
-  --> $DIR/min_match_ergonomics_fail.rs:44:9
+  --> $DIR/min_match_ergonomics_fail.rs:43:9
    |
 LL |         (&x,) => x,
    |         -^^^^
diff --git a/tests/ui/pattern/skipped-ref-pats-issue-125058.rs b/tests/ui/pattern/skipped-ref-pats-issue-125058.rs
index b733e5fda0a..2b587ecb91f 100644
--- a/tests/ui/pattern/skipped-ref-pats-issue-125058.rs
+++ b/tests/ui/pattern/skipped-ref-pats-issue-125058.rs
@@ -1,6 +1,5 @@
 //@ run-pass
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 
 #![allow(incomplete_features)]
 #![feature(ref_pat_eat_one_layer_2024)]
diff --git a/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr b/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
index cee1cc673c7..f7fd4a4cc29 100644
--- a/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
+++ b/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
@@ -1,5 +1,5 @@
 warning: struct `Foo` is never constructed
-  --> $DIR/skipped-ref-pats-issue-125058.rs:8:8
+  --> $DIR/skipped-ref-pats-issue-125058.rs:7:8
    |
 LL | struct Foo;
    |        ^^^
@@ -7,7 +7,7 @@ LL | struct Foo;
    = note: `#[warn(dead_code)]` on by default
 
 warning: unused closure that must be used
-  --> $DIR/skipped-ref-pats-issue-125058.rs:12:5
+  --> $DIR/skipped-ref-pats-issue-125058.rs:11:5
    |
 LL | /     || {
 LL | |
diff --git a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
index e4dd35a5995..60b4fcca286 100644
--- a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
+++ b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
@@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
    |
 LL |     match (true, false) {
    |           ^^^^^^^^^^^^^ pattern `(true, false)` not covered
+LL |
+LL |         TRUE_TRUE => (),
+   |         --------- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `TRUE_TRUE`
    |
    = note: the matched value is of type `(bool, bool)`
+note: constant `TRUE_TRUE` defined here
+  --> $DIR/match-arm-statics-2.rs:14:1
+   |
+LL | const TRUE_TRUE: (bool, bool) = (true, true);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         TRUE_TRUE_var => (),
+   |                  ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         (false, true) => (),
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
index a8786d02414..0a3991fe3d1 100644
--- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
@@ -199,8 +199,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         CONST => {},
@@ -212,8 +224,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         &[false] => {},
@@ -225,8 +249,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         CONST => {},
@@ -238,8 +274,20 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         CONST => {},
@@ -251,8 +299,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
    |
 LL |     match s {
    |           ^ pattern `&[false]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &[_, _, ..] => {},
@@ -264,8 +324,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
    |
 LL |     match s1 {
    |           ^^ pattern `&[false]` not covered
+LL |
+LL |         CONST1 => {}
+   |         ------ this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST1`
    |
    = note: the matched value is of type `&[bool; 1]`
+note: constant `CONST1` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:124:5
+   |
+LL |     const CONST1: &[bool; 1] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST1_var => {}
+   |               ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         CONST1 => {},
diff --git a/tests/ui/resolve/const-with-typo-in-pattern-binding.rs b/tests/ui/resolve/const-with-typo-in-pattern-binding.rs
new file mode 100644
index 00000000000..fe45cee91db
--- /dev/null
+++ b/tests/ui/resolve/const-with-typo-in-pattern-binding.rs
@@ -0,0 +1,45 @@
+#![deny(unreachable_patterns)] //~ NOTE the lint level is defined here
+#![allow(non_snake_case, non_upper_case_globals)]
+mod x {
+    pub use std::env::consts::ARCH;
+    const X: i32 = 0; //~ NOTE there is a constant of the same name
+}
+fn main() {
+    let input: i32 = 42;
+
+    const god: i32 = 1;
+    const GOOD: i32 = 1;
+    const BAD: i32 = 2;
+
+    let name: i32 = 42; //~ NOTE there is a binding of the same name
+
+    match input {
+        X => {} //~ NOTE matches any value
+        _ => {} //~ ERROR unreachable pattern
+        //~^ NOTE no value can reach this
+    }
+    match input {
+        GOD => {} //~ HELP you might have meant to pattern match against the value of similarly named constant `god`
+        //~^ NOTE matches any value
+        _ => {} //~ ERROR unreachable pattern
+        //~^ NOTE no value can reach this
+    }
+    match input {
+        GOOOD => {} //~ HELP you might have meant to pattern match against the value of similarly named constant `GOOD`
+        //~^ NOTE matches any value
+        _ => {} //~ ERROR unreachable pattern
+        //~^ NOTE no value can reach this
+    }
+    match input {
+        name => {}
+        //~^ NOTE matches any value
+        _ => {} //~ ERROR unreachable pattern
+        //~^ NOTE no value can reach this
+    }
+    match "" {
+        ARCH => {} //~ HELP you might have meant to pattern match against the value of constant `ARCH`
+        //~^ NOTE matches any value
+        _ => {} //~ ERROR unreachable pattern
+        //~^ NOTE no value can reach this
+    }
+}
diff --git a/tests/ui/resolve/const-with-typo-in-pattern-binding.stderr b/tests/ui/resolve/const-with-typo-in-pattern-binding.stderr
new file mode 100644
index 00000000000..a0cdac3fa25
--- /dev/null
+++ b/tests/ui/resolve/const-with-typo-in-pattern-binding.stderr
@@ -0,0 +1,78 @@
+error: unreachable pattern
+  --> $DIR/const-with-typo-in-pattern-binding.rs:18:9
+   |
+LL |         X => {}
+   |         - matches any value
+LL |         _ => {}
+   |         ^ no value can reach this
+   |
+note: there is a constant of the same name, which could have been used to pattern match against its value instead of introducing a new catch-all binding, but it is not accessible from this scope
+  --> $DIR/const-with-typo-in-pattern-binding.rs:5:5
+   |
+LL |     const X: i32 = 0;
+   |     ^^^^^^^^^^^^
+note: the lint level is defined here
+  --> $DIR/const-with-typo-in-pattern-binding.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/const-with-typo-in-pattern-binding.rs:24:9
+   |
+LL |         GOD => {}
+   |         --- matches any value
+LL |
+LL |         _ => {}
+   |         ^ no value can reach this
+   |
+help: you might have meant to pattern match against the value of similarly named constant `god` instead of introducing a new catch-all binding
+   |
+LL |         god => {}
+   |         ~~~
+
+error: unreachable pattern
+  --> $DIR/const-with-typo-in-pattern-binding.rs:30:9
+   |
+LL |         GOOOD => {}
+   |         ----- matches any value
+LL |
+LL |         _ => {}
+   |         ^ no value can reach this
+   |
+help: you might have meant to pattern match against the value of similarly named constant `GOOD` instead of introducing a new catch-all binding
+   |
+LL |         GOOD => {}
+   |         ~~~~
+
+error: unreachable pattern
+  --> $DIR/const-with-typo-in-pattern-binding.rs:36:9
+   |
+LL |         name => {}
+   |         ---- matches any value
+LL |
+LL |         _ => {}
+   |         ^ no value can reach this
+   |
+note: there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings
+  --> $DIR/const-with-typo-in-pattern-binding.rs:14:9
+   |
+LL |     let name: i32 = 42;
+   |         ^^^^
+
+error: unreachable pattern
+  --> $DIR/const-with-typo-in-pattern-binding.rs:42:9
+   |
+LL |         ARCH => {}
+   |         ---- matches any value
+LL |
+LL |         _ => {}
+   |         ^ no value can reach this
+   |
+help: you might have meant to pattern match against the value of constant `ARCH` instead of introducing a new catch-all binding
+   |
+LL |         std::env::consts::ARCH => {}
+   |         ~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
index 389c76337f0..2c7fe2eea33 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
@@ -1,5 +1,5 @@
 // issue-103476
-//@ compile-flags: -Zlint-mir -Zunstable-options
+//@ compile-flags: -Zlint-mir
 //@ edition: 2024
 //@ check-pass
 
diff --git a/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs
index 2c3dc30f0ae..aa655942150 100644
--- a/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs
+++ b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs
@@ -1,5 +1,4 @@
 //@ force-host
-//@ compile-flags: -Zunstable-options
 //@ edition:2024
 //@ no-prefer-dynamic
 
diff --git a/tests/ui/rust-2024/prelude2024.rs b/tests/ui/rust-2024/prelude2024.rs
index e58ebe74188..b7573948d9a 100644
--- a/tests/ui/rust-2024/prelude2024.rs
+++ b/tests/ui/rust-2024/prelude2024.rs
@@ -1,5 +1,4 @@
 //@ check-pass
-//@ compile-flags: -Zunstable-options
 //@ edition:2024
 
 fn main() {
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs
index f9e3c1e3c51..882f52c48a6 100644
--- a/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs
+++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs
@@ -1,5 +1,4 @@
 //@ run-pass
-//@ compile-flags: -Zunstable-options
 //@ edition:2024
 //@ aux-build:reserved-guarded-strings-macro-2021.rs
 
diff --git a/tests/ui/rust-2024/reserved-guarded-strings.rs b/tests/ui/rust-2024/reserved-guarded-strings.rs
index dab97039be0..878881c1d24 100644
--- a/tests/ui/rust-2024/reserved-guarded-strings.rs
+++ b/tests/ui/rust-2024/reserved-guarded-strings.rs
@@ -1,4 +1,3 @@
-//@ compile-flags: -Zunstable-options
 //@ edition:2024
 // ignore-tidy-linelength
 
diff --git a/tests/ui/rust-2024/reserved-guarded-strings.stderr b/tests/ui/rust-2024/reserved-guarded-strings.stderr
index f465ba7944a..c8f8557b0f4 100644
--- a/tests/ui/rust-2024/reserved-guarded-strings.stderr
+++ b/tests/ui/rust-2024/reserved-guarded-strings.stderr
@@ -1,5 +1,5 @@
 error: prefix `blah` is unknown
-  --> $DIR/reserved-guarded-strings.rs:45:12
+  --> $DIR/reserved-guarded-strings.rs:44:12
    |
 LL |     demo2!(blah"xx");
    |            ^^^^ unknown prefix
@@ -11,7 +11,7 @@ LL |     demo2!(blah "xx");
    |                +
 
 error: prefix `blah` is unknown
-  --> $DIR/reserved-guarded-strings.rs:46:12
+  --> $DIR/reserved-guarded-strings.rs:45:12
    |
 LL |     demo2!(blah#"xx"#);
    |            ^^^^ unknown prefix
@@ -23,7 +23,7 @@ LL |     demo2!(blah #"xx"#);
    |                +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:46:16
+  --> $DIR/reserved-guarded-strings.rs:45:16
    |
 LL |     demo2!(blah#"xx"#);
    |                ^^^^^^
@@ -35,7 +35,7 @@ LL |     demo2!(blah# "xx"#);
    |                 +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:50:12
+  --> $DIR/reserved-guarded-strings.rs:49:12
    |
 LL |     demo2!(## "foo");
    |            ^^
@@ -47,7 +47,7 @@ LL |     demo2!(# # "foo");
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:51:17
+  --> $DIR/reserved-guarded-strings.rs:50:17
    |
 LL |     demo3!("foo"###);
    |                 ^^
@@ -59,7 +59,7 @@ LL |     demo3!("foo"# ##);
    |                  +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:52:12
+  --> $DIR/reserved-guarded-strings.rs:51:12
    |
 LL |     demo3!(### "foo");
    |            ^^
@@ -71,7 +71,7 @@ LL |     demo3!(# ## "foo");
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:53:12
+  --> $DIR/reserved-guarded-strings.rs:52:12
    |
 LL |     demo3!(## "foo"#);
    |            ^^
@@ -83,7 +83,7 @@ LL |     demo3!(# # "foo"#);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:54:12
+  --> $DIR/reserved-guarded-strings.rs:53:12
    |
 LL |     demo5!(### "foo"###);
    |            ^^
@@ -95,7 +95,7 @@ LL |     demo5!(# ## "foo"###);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:54:21
+  --> $DIR/reserved-guarded-strings.rs:53:21
    |
 LL |     demo5!(### "foo"###);
    |                     ^^
@@ -107,7 +107,7 @@ LL |     demo5!(### "foo"# ##);
    |                      +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:58:12
+  --> $DIR/reserved-guarded-strings.rs:57:12
    |
 LL |     demo1!(#"");
    |            ^^^
@@ -119,7 +119,7 @@ LL |     demo1!(# "");
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:59:12
+  --> $DIR/reserved-guarded-strings.rs:58:12
    |
 LL |     demo1!(#""#);
    |            ^^^^
@@ -131,7 +131,7 @@ LL |     demo1!(# ""#);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:60:12
+  --> $DIR/reserved-guarded-strings.rs:59:12
    |
 LL |     demo1!(####"");
    |            ^^^^^^
@@ -143,7 +143,7 @@ LL |     demo1!(# ###"");
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:61:12
+  --> $DIR/reserved-guarded-strings.rs:60:12
    |
 LL |     demo1!(#"foo");
    |            ^^^^^^
@@ -155,7 +155,7 @@ LL |     demo1!(# "foo");
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:62:12
+  --> $DIR/reserved-guarded-strings.rs:61:12
    |
 LL |     demo1!(###"foo");
    |            ^^^^^^^^
@@ -167,7 +167,7 @@ LL |     demo1!(# ##"foo");
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:63:12
+  --> $DIR/reserved-guarded-strings.rs:62:12
    |
 LL |     demo1!(#"foo"#);
    |            ^^^^^^^
@@ -179,7 +179,7 @@ LL |     demo1!(# "foo"#);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:64:12
+  --> $DIR/reserved-guarded-strings.rs:63:12
    |
 LL |     demo1!(###"foo"#);
    |            ^^^^^^^^^
@@ -191,7 +191,7 @@ LL |     demo1!(# ##"foo"#);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:65:12
+  --> $DIR/reserved-guarded-strings.rs:64:12
    |
 LL |     demo1!(###"foo"##);
    |            ^^^^^^^^^^
@@ -203,7 +203,7 @@ LL |     demo1!(# ##"foo"##);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:66:12
+  --> $DIR/reserved-guarded-strings.rs:65:12
    |
 LL |     demo1!(###"foo"###);
    |            ^^^^^^^^^^^
@@ -215,7 +215,7 @@ LL |     demo1!(# ##"foo"###);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:67:12
+  --> $DIR/reserved-guarded-strings.rs:66:12
    |
 LL |     demo2!(#"foo"###);
    |            ^^^^^^^
@@ -227,7 +227,7 @@ LL |     demo2!(# "foo"###);
    |             +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:67:19
+  --> $DIR/reserved-guarded-strings.rs:66:19
    |
 LL |     demo2!(#"foo"###);
    |                   ^^
@@ -239,7 +239,7 @@ LL |     demo2!(#"foo"## #);
    |                    +
 
 error: invalid string literal
-  --> $DIR/reserved-guarded-strings.rs:72:12
+  --> $DIR/reserved-guarded-strings.rs:71:12
    |
 LL | ...n!(####################################################################################################################################################################################################################################################################"foo...
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/sanitizer/cfi/coroutine.rs b/tests/ui/sanitizer/cfi/coroutine.rs
index ad994fcf737..ec7c5888968 100644
--- a/tests/ui/sanitizer/cfi/coroutine.rs
+++ b/tests/ui/sanitizer/cfi/coroutine.rs
@@ -11,7 +11,7 @@
 //@ [cfi] compile-flags: -Z sanitizer=cfi
 //@ [kcfi] compile-flags: -Z sanitizer=kcfi
 //@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
-//@ compile-flags: --test -Z unstable-options
+//@ compile-flags: --test
 //@ run-pass
 
 #![feature(coroutines, stmt_expr_attributes)]
diff --git a/tests/ui/simd-abi-checks-s390x.rs b/tests/ui/simd-abi-checks-s390x.rs
new file mode 100644
index 00000000000..15df66a2ced
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.rs
@@ -0,0 +1,174 @@
+//@ revisions: z10 z13_no_vector z13_soft_float
+//@ build-fail
+//@[z10] compile-flags: --target s390x-unknown-linux-gnu
+//@[z10] needs-llvm-components: systemz
+//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector
+//@[z13_no_vector] needs-llvm-components: systemz
+// FIXME: +soft-float itself doesn't set -vector
+//@[z13_soft_float] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector,+soft-float
+//@[z13_soft_float] needs-llvm-components: systemz
+
+#![feature(no_core, lang_items, repr_simd, s390x_target_feature)]
+#![no_core]
+#![crate_type = "lib"]
+#![allow(non_camel_case_types, improper_ctypes_definitions)]
+#![deny(abi_unsupported_vector_types)]
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+#[lang = "freeze"]
+pub trait Freeze {}
+
+impl<T: Copy, const N: usize> Copy for [T; N] {}
+
+#[repr(simd)]
+pub struct i8x8([i8; 8]);
+#[repr(simd)]
+pub struct i8x16([i8; 16]);
+#[repr(simd)]
+pub struct i8x32([i8; 32]);
+#[repr(C)]
+pub struct Wrapper<T>(T);
+#[repr(transparent)]
+pub struct TransparentWrapper<T>(T);
+
+impl Copy for i8 {}
+impl Copy for i64 {}
+impl Copy for i8x8 {}
+impl Copy for i8x16 {}
+impl Copy for i8x32 {}
+impl<T: Copy> Copy for Wrapper<T> {}
+impl<T: Copy> Copy for TransparentWrapper<T> {}
+
+#[no_mangle]
+extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+#[target_feature(enable = "vector")]
+unsafe extern "C" fn vector_ret_target_feature_small(x: &i8x8) -> i8x8 {
+    // Ok
+    *x
+}
+#[no_mangle]
+#[target_feature(enable = "vector")]
+unsafe extern "C" fn vector_target_feature_ret(x: &i8x16) -> i8x16 {
+    // Ok
+    *x
+}
+#[no_mangle]
+#[target_feature(enable = "vector")]
+unsafe extern "C" fn vector_ret_target_feature_large(x: &i8x32) -> i8x32 {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+extern "C" fn vector_wrapper_ret_small(x: &Wrapper<i8x8>) -> Wrapper<i8x8> {
+    // Ok
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_ret(x: &Wrapper<i8x16>) -> Wrapper<i8x16> {
+    // Ok
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_ret_large(x: &Wrapper<i8x32>) -> Wrapper<i8x32> {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_ret_small(
+    x: &TransparentWrapper<i8x8>,
+) -> TransparentWrapper<i8x8> {
+    //~^^^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_ret(
+    x: &TransparentWrapper<i8x16>,
+) -> TransparentWrapper<i8x16> {
+    //~^^^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^^^ WARN this was previously accepted
+    *x
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_ret_large(
+    x: &TransparentWrapper<i8x32>,
+) -> TransparentWrapper<i8x32> {
+    // Ok
+    *x
+}
+
+#[no_mangle]
+extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const i8x8 as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_arg(x: i8x16) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const i8x16 as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_arg_large(x: i8x32) -> i64 {
+    // Ok
+    unsafe { *(&x as *const i8x32 as *const i64) }
+}
+
+#[no_mangle]
+extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const Wrapper<i8x8> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const Wrapper<i8x16> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 {
+    // Ok
+    unsafe { *(&x as *const Wrapper<i8x32> as *const i64) }
+}
+
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+    //~^ ERROR this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+    //~^^ WARN this was previously accepted
+    unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) }
+}
+#[no_mangle]
+extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 {
+    // Ok
+    unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) }
+}
diff --git a/tests/ui/simd-abi-checks-s390x.z10.stderr b/tests/ui/simd-abi-checks-s390x.z10.stderr
new file mode 100644
index 00000000000..a91322ec058
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.z10.stderr
@@ -0,0 +1,111 @@
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:46:1
+   |
+LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+note: the lint level is defined here
+  --> $DIR/simd-abi-checks-s390x.rs:15:9
+   |
+LL | #![deny(abi_unsupported_vector_types)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:52:1
+   |
+LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:99:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret_small(
+LL | |     x: &TransparentWrapper<i8x8>,
+LL | | ) -> TransparentWrapper<i8x8> {
+   | |_____________________________^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:107:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret(
+LL | |     x: &TransparentWrapper<i8x16>,
+LL | | ) -> TransparentWrapper<i8x16> {
+   | |______________________________^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:123:1
+   |
+LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:129:1
+   |
+LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:141:1
+   |
+LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:147:1
+   |
+LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:159:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:165:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr
new file mode 100644
index 00000000000..a91322ec058
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.z13_no_vector.stderr
@@ -0,0 +1,111 @@
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:46:1
+   |
+LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+note: the lint level is defined here
+  --> $DIR/simd-abi-checks-s390x.rs:15:9
+   |
+LL | #![deny(abi_unsupported_vector_types)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:52:1
+   |
+LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:99:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret_small(
+LL | |     x: &TransparentWrapper<i8x8>,
+LL | | ) -> TransparentWrapper<i8x8> {
+   | |_____________________________^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:107:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret(
+LL | |     x: &TransparentWrapper<i8x16>,
+LL | | ) -> TransparentWrapper<i8x16> {
+   | |______________________________^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:123:1
+   |
+LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:129:1
+   |
+LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:141:1
+   |
+LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:147:1
+   |
+LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:159:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:165:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr
new file mode 100644
index 00000000000..a91322ec058
--- /dev/null
+++ b/tests/ui/simd-abi-checks-s390x.z13_soft_float.stderr
@@ -0,0 +1,111 @@
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:46:1
+   |
+LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+note: the lint level is defined here
+  --> $DIR/simd-abi-checks-s390x.rs:15:9
+   |
+LL | #![deny(abi_unsupported_vector_types)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:52:1
+   |
+LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:99:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret_small(
+LL | |     x: &TransparentWrapper<i8x8>,
+LL | | ) -> TransparentWrapper<i8x8> {
+   | |_____________________________^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:107:1
+   |
+LL | / extern "C" fn vector_transparent_wrapper_ret(
+LL | |     x: &TransparentWrapper<i8x16>,
+LL | | ) -> TransparentWrapper<i8x16> {
+   | |______________________________^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:123:1
+   |
+LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:129:1
+   |
+LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:141:1
+   |
+LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:147:1
+   |
+LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:159:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: this function definition uses a SIMD vector type that (with the chosen ABI) requires the `vector` target feature, which is not enabled
+  --> $DIR/simd-abi-checks-s390x.rs:165:1
+   |
+LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
+   |
+   = 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 #116558 <https://github.com/rust-lang/rust/issues/116558>
+   = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
index 60433e1c284..5ecbedf1867 100644
--- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
+++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
@@ -4,7 +4,7 @@ error[E0670]: `async fn` is not permitted in Rust 2015
 LL |     pub(crate) async fn new(
    |                ^^^^^ to use `async fn`, switch to Rust 2018 or later
    |
-   = help: pass `--edition 2021` to `rustc`
+   = help: pass `--edition 2024` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0412]: cannot find type `Duration` in this scope
diff --git a/tests/ui/specialization/issue-68830-spurious-diagnostics.rs b/tests/ui/specialization/issue-68830-spurious-diagnostics.rs
index a7487b8aecb..d11ec798332 100644
--- a/tests/ui/specialization/issue-68830-spurious-diagnostics.rs
+++ b/tests/ui/specialization/issue-68830-spurious-diagnostics.rs
@@ -17,7 +17,6 @@ impl<T, D> MyTrait<T> for D {
 }
 
 impl<T> MyTrait<T> for BadStruct {
-//~^ ERROR: conflicting implementations of trait `MyTrait<_>` for type `BadStruct`
     fn foo() {}
 }
 
diff --git a/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr b/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr
index 13f6ae0805d..0ecec03a023 100644
--- a/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr
+++ b/tests/ui/specialization/issue-68830-spurious-diagnostics.stderr
@@ -4,16 +4,6 @@ error[E0412]: cannot find type `MissingType` in this scope
 LL |     err: MissingType
    |          ^^^^^^^^^^^ not found in this scope
 
-error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `BadStruct`
-  --> $DIR/issue-68830-spurious-diagnostics.rs:19:1
-   |
-LL | impl<T, D> MyTrait<T> for D {
-   | --------------------------- first implementation here
-...
-LL | impl<T> MyTrait<T> for BadStruct {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `BadStruct`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0119, E0412.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr b/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr
index 2af75876d5b..04a41f0d9dd 100644
--- a/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr
+++ b/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr
@@ -4,11 +4,7 @@ error[E0477]: the type `&'a i32` does not fulfill the required lifetime
 LL | impl<'a> Tr for &'a i32 {
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/specialize_with_generalize_lifetimes.rs:12:15
-   |
-LL | impl<T: Any + 'static> Tr for T {
-   |               ^^^^^^^
+   = note: type must satisfy the static lifetime
 
 error[E0477]: the type `Wrapper<'a>` does not fulfill the required lifetime
   --> $DIR/specialize_with_generalize_lifetimes.rs:31:1
@@ -16,11 +12,7 @@ error[E0477]: the type `Wrapper<'a>` does not fulfill the required lifetime
 LL | impl<'a> Tr for Wrapper<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/specialize_with_generalize_lifetimes.rs:12:15
-   |
-LL | impl<T: Any + 'static> Tr for T {
-   |               ^^^^^^^
+   = note: type must satisfy the static lifetime
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 05e087fd9f9..a040e71cf3b 100644
--- a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -31,6 +31,10 @@ note: required by a bound in `bar`
    |
 LL | fn bar(f: impl Future<Output=()>) {}
    |                ^^^^^^^^^^^^^^^^^ required by this bound in `bar`
+help: use parentheses to call this closure
+   |
+LL |     bar(async_closure());
+   |                      ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
index af47ba8baa3..1a440a90cd7 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
@@ -2,9 +2,9 @@ fn main() {
     let A = 3;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-    //~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     //~| SUGGESTION A_var
 
     const A: i32 = 2;
+    //~^ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
 }
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
index b6c28612802..a275d8e4e83 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
@@ -2,15 +2,18 @@ error[E0005]: refutable pattern in local binding
   --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
    |
 LL |     let A = 3;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
-   |         help: introduce a variable instead: `A_var`
+   |         ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
+...
+LL |     const A: i32 = 2;
+   |     ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let A_var = 3;
+   |         ~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout
index 1840be7885b..5588cfdfa5c 100644
--- a/tests/ui/thir-print/thir-flat-const-variant.stdout
+++ b/tests/ui/thir-print/thir-flat-const-variant.stdout
@@ -11,9 +11,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0),
         },
         Expr {
@@ -25,9 +28,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0),
         },
         Expr {
@@ -47,9 +53,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0),
         },
         Expr {
@@ -61,9 +70,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0),
         },
     ],
@@ -84,9 +96,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0),
         },
         Expr {
@@ -98,9 +113,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0),
         },
         Expr {
@@ -120,9 +138,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0),
         },
         Expr {
@@ -134,9 +155,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0),
         },
     ],
@@ -157,9 +181,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0),
         },
         Expr {
@@ -171,9 +198,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0),
         },
         Expr {
@@ -193,9 +223,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0),
         },
         Expr {
@@ -207,9 +240,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0),
         },
     ],
@@ -230,9 +266,12 @@ Thir {
                 fields: [],
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0),
         },
         Expr {
@@ -244,9 +283,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0),
         },
         Expr {
@@ -266,9 +308,12 @@ Thir {
                 },
             ),
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0),
         },
         Expr {
@@ -280,9 +325,12 @@ Thir {
                 value: e2,
             },
             ty: Foo,
-            temp_lifetime: Some(
-                Node(3),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(3),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0),
         },
     ],
@@ -312,9 +360,12 @@ Thir {
                 block: b0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0),
         },
         Expr {
@@ -326,9 +377,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0),
         },
     ],
diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout
index a31d08adab6..59cecfe511c 100644
--- a/tests/ui/thir-print/thir-flat.stdout
+++ b/tests/ui/thir-print/thir-flat.stdout
@@ -20,9 +20,12 @@ Thir {
                 block: b0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
         },
         Expr {
@@ -34,9 +37,12 @@ Thir {
                 value: e0,
             },
             ty: (),
-            temp_lifetime: Some(
-                Node(2),
-            ),
+            temp_lifetime: TempLifetime {
+                temp_lifetime: Some(
+                    Node(2),
+                ),
+                backwards_incompatible: None,
+            },
             span: $DIR/thir-flat.rs:4:15: 4:17 (#0),
         },
     ],
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 8cff7887661..a9d6985928a 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -26,7 +26,7 @@ params: [
 body:
     Expr {
         ty: bool
-        temp_lifetime: Some(Node(26))
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
         kind: 
             Scope {
@@ -35,7 +35,7 @@ body:
                 value:
                     Expr {
                         ty: bool
-                        temp_lifetime: Some(Node(26))
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
                         kind: 
                             Block {
@@ -47,7 +47,7 @@ body:
                                 expr:
                                     Expr {
                                         ty: bool
-                                        temp_lifetime: Some(Node(26))
+                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                         kind: 
                                             Scope {
@@ -56,14 +56,14 @@ body:
                                                 value:
                                                     Expr {
                                                         ty: bool
-                                                        temp_lifetime: Some(Node(26))
+                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                                         kind: 
                                                             Match {
                                                                 scrutinee:
                                                                     Expr {
                                                                         ty: Foo
-                                                                        temp_lifetime: Some(Node(26))
+                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                         kind: 
                                                                             Scope {
@@ -72,7 +72,7 @@ body:
                                                                                 value:
                                                                                     Expr {
                                                                                         ty: Foo
-                                                                                        temp_lifetime: Some(Node(26))
+                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                         kind: 
                                                                                             VarRef {
@@ -123,7 +123,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(13))
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -132,7 +132,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(13))
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@@ -175,7 +175,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(19))
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -184,7 +184,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(19))
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@@ -219,7 +219,7 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(24))
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                 kind: 
                                                                                     Scope {
@@ -228,7 +228,7 @@ body:
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(24))
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
@@ -257,7 +257,7 @@ params: [
 body:
     Expr {
         ty: ()
-        temp_lifetime: Some(Node(2))
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
         span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
         kind: 
             Scope {
@@ -266,7 +266,7 @@ body:
                 value:
                     Expr {
                         ty: ()
-                        temp_lifetime: Some(Node(2))
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
                         span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0)
                         kind: 
                             Block {
diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout
index ef6db368dbe..b39581ad841 100644
--- a/tests/ui/thir-print/thir-tree.stdout
+++ b/tests/ui/thir-print/thir-tree.stdout
@@ -4,7 +4,7 @@ params: [
 body:
     Expr {
         ty: ()
-        temp_lifetime: Some(Node(2))
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
         span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
         kind: 
             Scope {
@@ -13,7 +13,7 @@ body:
                 value:
                     Expr {
                         ty: ()
-                        temp_lifetime: Some(Node(2))
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
                         span: $DIR/thir-tree.rs:4:15: 4:17 (#0)
                         kind: 
                             Block {
diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
index 2cb63f25d06..fd0e9691700 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.rs
@@ -1,7 +1,7 @@
 trait Trait {}
 
 fn test<T: ?self::<i32>::Trait>() {}
-//~^ ERROR type arguments are not allowed on this type
+//~^ ERROR type arguments are not allowed on module `maybe_bound_has_path_args`
 //~| WARN relaxing a default bound only does something for `?Sized`
 
 fn main() {}
diff --git a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
index 701e493f5a5..0c167fff940 100644
--- a/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
+++ b/tests/ui/trait-bounds/maybe-bound-has-path-args.stderr
@@ -4,13 +4,13 @@ warning: relaxing a default bound only does something for `?Sized`; all other tr
 LL | fn test<T: ?self::<i32>::Trait>() {}
    |            ^^^^^^^^^^^^^^^^^^^
 
-error[E0109]: type arguments are not allowed on this type
+error[E0109]: type arguments are not allowed on module `maybe_bound_has_path_args`
   --> $DIR/maybe-bound-has-path-args.rs:3:20
    |
 LL | fn test<T: ?self::<i32>::Trait>() {}
    |             ----   ^^^ type argument not allowed
    |             |
-   |             not allowed on this type
+   |             not allowed on module `maybe_bound_has_path_args`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
index 25c81ff900f..0970cd5225f 100644
--- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
@@ -12,5 +12,13 @@ LL | const fn test() -> impl ~const Fn() {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 2 previous errors
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-parse-not-item.rs:7:25
+   |
+LL | const fn test() -> impl ~const Fn() {
+   |                         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr
new file mode 100644
index 00000000000..e43a6b603fd
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-opaque.no.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `(): const Foo` is not satisfied
+  --> $DIR/const-opaque.rs:31:18
+   |
+LL |     let opaque = bar(());
+   |                  ^^^^^^^
+
+error[E0277]: the trait bound `(): const Foo` is not satisfied
+  --> $DIR/const-opaque.rs:33:5
+   |
+LL |     opaque.method();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/const-opaque.rs b/tests/ui/traits/const-traits/const-opaque.rs
new file mode 100644
index 00000000000..96cdd7d9f26
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-opaque.rs
@@ -0,0 +1,38 @@
+//@ revisions: yes no
+//@ compile-flags: -Znext-solver
+//@[yes] check-pass
+
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Foo {
+    fn method(&self);
+}
+
+impl<T: ~const Foo> const Foo for (T,) {
+    fn method(&self) {}
+}
+
+#[cfg(yes)]
+impl const Foo for () {
+    fn method(&self) {}
+}
+
+#[cfg(no)]
+impl Foo for () {
+    fn method(&self) {}
+}
+
+const fn bar<T: ~const Foo>(t: T) -> impl ~const Foo {
+    (t,)
+}
+
+const _: () = {
+    let opaque = bar(());
+    //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied
+    opaque.method();
+    //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied
+    std::mem::forget(opaque);
+};
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/effects/dont-prefer-param-env-for-infer-self-ty.rs b/tests/ui/traits/const-traits/effects/dont-prefer-param-env-for-infer-self-ty.rs
new file mode 100644
index 00000000000..08dcd7d80b3
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/dont-prefer-param-env-for-infer-self-ty.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Foo {}
+
+impl<T> const Foo for (T,) where T: ~const Foo {}
+
+const fn needs_const_foo(_: impl ~const Foo + Copy) {}
+
+const fn test<T: ~const Foo + Copy>(t: T) {
+    needs_const_foo((t,));
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
index c467088ab3d..8ff15dd09cc 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
@@ -3,6 +3,7 @@
 const fn test() -> impl ~const Fn() {
     //~^ ERROR `~const` can only be applied to `#[const_trait]` traits
     //~| ERROR `~const` can only be applied to `#[const_trait]` traits
+    //~| ERROR `~const` can only be applied to `#[const_trait]` traits
     const move || { //~ ERROR const closures are experimental
         let sl: &[u8] = b"foo";
 
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
index 6d7edaf19f2..879d966b1f9 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
@@ -1,5 +1,5 @@
 error[E0658]: const closures are experimental
-  --> $DIR/ice-112822-expected-type-for-param.rs:6:5
+  --> $DIR/ice-112822-expected-type-for-param.rs:7:5
    |
 LL |     const move || {
    |     ^^^^^
@@ -22,8 +22,16 @@ LL | const fn test() -> impl ~const Fn() {
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/ice-112822-expected-type-for-param.rs:3:25
+   |
+LL | const fn test() -> impl ~const Fn() {
+   |                         ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/ice-112822-expected-type-for-param.rs:11:17
+  --> $DIR/ice-112822-expected-type-for-param.rs:12:17
    |
 LL |                 assert_eq!(first, &b'f');
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +40,7 @@ LL |                 assert_eq!(first, &b'f');
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions
-  --> $DIR/ice-112822-expected-type-for-param.rs:11:17
+  --> $DIR/ice-112822-expected-type-for-param.rs:12:17
    |
 LL |                 assert_eq!(first, &b'f');
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +48,7 @@ LL |                 assert_eq!(first, &b'f');
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0015, E0658.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs
index a08407683d8..85c70a21f68 100644
--- a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs
+++ b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs
@@ -1,5 +1,6 @@
 fn function<T: PartialEq>() {
     foo == 2; //~ ERROR cannot find value `foo` in this scope [E0425]
+    //~^ ERROR mismatched types
 }
 
 fn main() {}
diff --git a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr
index 2da731dcc4b..8010c0842ba 100644
--- a/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr
+++ b/tests/ui/traits/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.stderr
@@ -4,6 +4,18 @@ error[E0425]: cannot find value `foo` in this scope
 LL |     foo == 2;
    |     ^^^ not found in this scope
 
-error: aborting due to 1 previous error
+error[E0308]: mismatched types
+  --> $DIR/dont-match-error-ty-with-calller-supplied-obligation-issue-121941.rs:2:12
+   |
+LL | fn function<T: PartialEq>() {
+   |             - expected this type parameter
+LL |     foo == 2;
+   |            ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0425`.
+Some errors have detailed explanations: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/issue-78372.rs b/tests/ui/traits/issue-78372.rs
index 82b13cc0b62..f03baf2ceca 100644
--- a/tests/ui/traits/issue-78372.rs
+++ b/tests/ui/traits/issue-78372.rs
@@ -10,5 +10,4 @@ trait X<T> {
 }
 trait Marker {}
 impl Marker for dyn Foo {}
-//~^ ERROR cannot be made into an object
 fn main() {}
diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr
index 4cc2c59fd8d..86234d15a5d 100644
--- a/tests/ui/traits/issue-78372.stderr
+++ b/tests/ui/traits/issue-78372.stderr
@@ -55,24 +55,6 @@ LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
    = help: add `#![feature(dispatch_from_dyn)]` 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[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/issue-78372.rs:12:17
-   |
-LL |     fn foo(self: Smaht<Self, T>);
-   |                  -------------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
-...
-LL | impl Marker for dyn Foo {}
-   |                 ^^^^^^^ `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/issue-78372.rs:9:18
-   |
-LL | trait Foo: X<u32> {}
-   |       --- this trait cannot be made into an object...
-LL | trait X<T> {
-LL |     fn foo(self: Smaht<Self, T>);
-   |                  ^^^^^^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
-
 error[E0307]: invalid `self` parameter type: `Smaht<Self, T>`
   --> $DIR/issue-78372.rs:9:18
    |
@@ -88,7 +70,7 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion
 LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0038, E0307, E0378, E0412, E0658.
-For more information about an error, try `rustc --explain E0038`.
+Some errors have detailed explanations: E0307, E0378, E0412, E0658.
+For more information about an error, try `rustc --explain E0307`.
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
index 3af299e5b11..4aadd45c49c 100644
--- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
@@ -10,6 +10,7 @@ fn w<'a, T: 'a, F: Fn(&'a T)>() {
     let b: &dyn FromResidual = &();
     //~^ ERROR: the trait `FromResidual` cannot be made into an object
     //~| ERROR: the trait `FromResidual` cannot be made into an object
+    //~| ERROR: the trait `FromResidual` cannot be made into an object
 }
 
 fn main() {}
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
index 960802e2f8f..c67a8c05379 100644
--- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
@@ -7,6 +7,29 @@ LL |     let b: &dyn FromResidual = &();
    = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
 
 error[E0038]: the trait `FromResidual` cannot be made into an object
+  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:32
+   |
+LL |     let b: &dyn FromResidual = &();
+   |                                ^^^ `FromResidual` 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/canonicalize-fresh-infer-vars-issue-103626.rs:2:8
+   |
+LL | trait FromResidual<R = <Self as Try>::Residual> {
+   |       ------------ this trait cannot be made into an object...
+LL |     fn from_residual(residual: R) -> Self;
+   |        ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter
+   = note: required for the cast from `&()` to `&dyn FromResidual<{type error}>`
+help: consider turning `from_residual` into a method by giving it a `&self` argument
+   |
+LL |     fn from_residual(&self, residual: R) -> Self;
+   |                      ++++++
+help: alternatively, consider constraining `from_residual` so it does not apply to trait objects
+   |
+LL |     fn from_residual(residual: R) -> Self where Self: Sized;
+   |                                           +++++++++++++++++
+
+error[E0038]: the trait `FromResidual` cannot be made into an object
   --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12
    |
 LL |     let b: &dyn FromResidual = &();
@@ -28,6 +51,6 @@ help: alternatively, consider constraining `from_residual` so it does not apply
 LL |     fn from_residual(residual: R) -> Self where Self: Sized;
    |                                           +++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/span-bug-issue-121414.rs b/tests/ui/traits/span-bug-issue-121414.rs
index ec38d8c2de6..2f4ad34f0c8 100644
--- a/tests/ui/traits/span-bug-issue-121414.rs
+++ b/tests/ui/traits/span-bug-issue-121414.rs
@@ -6,8 +6,7 @@ impl<'a> Bar for Foo<'f> { //~ ERROR undeclared lifetime
     type Type = u32;
 }
 
-fn test() //~ ERROR the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
-          //~| ERROR the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
+fn test()
 where
     for<'a> <Foo<'a> as Bar>::Type: Sized,
 {
diff --git a/tests/ui/traits/span-bug-issue-121414.stderr b/tests/ui/traits/span-bug-issue-121414.stderr
index e2ef6672cd5..744806a3415 100644
--- a/tests/ui/traits/span-bug-issue-121414.stderr
+++ b/tests/ui/traits/span-bug-issue-121414.stderr
@@ -6,22 +6,6 @@ LL | impl<'a> Bar for Foo<'f> {
    |      |
    |      help: consider introducing lifetime `'f` here: `'f,`
 
-error[E0277]: the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
-  --> $DIR/span-bug-issue-121414.rs:9:1
-   |
-LL | / fn test()
-LL | |
-LL | | where
-LL | |     for<'a> <Foo<'a> as Bar>::Type: Sized,
-   | |__________________________________________^ the trait `for<'a> Bar` is not implemented for `Foo<'a>`
-
-error[E0277]: the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
-  --> $DIR/span-bug-issue-121414.rs:9:4
-   |
-LL | fn test()
-   |    ^^^^ the trait `for<'a> Bar` is not implemented for `Foo<'a>`
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0261, E0277.
-For more information about an error, try `rustc --explain E0261`.
+For more information about this error, try `rustc --explain E0261`.
diff --git a/tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs
new file mode 100644
index 00000000000..18cfb1c1f93
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.rs
@@ -0,0 +1,21 @@
+// regression test for #127353
+
+#![feature(type_alias_impl_trait)]
+trait Trait<T> {}
+type Alias<'a, U> = impl Trait<U>;
+//~^ ERROR unconstrained opaque type
+
+pub enum UninhabitedVariants {
+    Tuple(Alias),
+    //~^ ERROR missing lifetime specifier
+    //~| ERROR missing generics
+    //~| ERROR non-defining opaque type use in defining scope
+}
+
+fn uwu(x: UninhabitedVariants) {
+    //~^ ERROR item does not constrain
+    match x {}
+    //~^ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr
new file mode 100644
index 00000000000..cf366c55ea8
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/bad-tait-no-substs.stderr
@@ -0,0 +1,86 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/bad-tait-no-substs.rs:9:11
+   |
+LL |     Tuple(Alias),
+   |           ^^^^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL ~ pub enum UninhabitedVariants<'a> {
+LL ~     Tuple(Alias<'a>),
+   |
+
+error[E0107]: missing generics for type alias `Alias`
+  --> $DIR/bad-tait-no-substs.rs:9:11
+   |
+LL |     Tuple(Alias),
+   |           ^^^^^ expected 1 generic argument
+   |
+note: type alias defined here, with 1 generic parameter: `U`
+  --> $DIR/bad-tait-no-substs.rs:5:6
+   |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |      ^^^^^     -
+help: add missing generic argument
+   |
+LL |     Tuple(Alias<U>),
+   |                +++
+
+error[E0792]: non-defining opaque type use in defining scope
+  --> $DIR/bad-tait-no-substs.rs:9:11
+   |
+LL |     Tuple(Alias),
+   |           ^^^^^ argument `'_` is not a generic parameter
+   |
+note: for this opaque type
+  --> $DIR/bad-tait-no-substs.rs:5:21
+   |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |                     ^^^^^^^^^^^^^
+
+error: item does not constrain `Alias::{opaque#0}`, but has it in its signature
+  --> $DIR/bad-tait-no-substs.rs:15:4
+   |
+LL | fn uwu(x: UninhabitedVariants) {
+   |    ^^^
+   |
+   = note: consider moving the opaque type's declaration and defining uses into a separate module
+note: this opaque type is in the signature
+  --> $DIR/bad-tait-no-substs.rs:5:21
+   |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |                     ^^^^^^^^^^^^^
+
+error: unconstrained opaque type
+  --> $DIR/bad-tait-no-substs.rs:5:21
+   |
+LL | type Alias<'a, U> = impl Trait<U>;
+   |                     ^^^^^^^^^^^^^
+   |
+   = note: `Alias` must be used in combination with a concrete type within the same module
+
+error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` not covered
+  --> $DIR/bad-tait-no-substs.rs:17:11
+   |
+LL |     match x {}
+   |           ^ pattern `UninhabitedVariants::Tuple(_)` not covered
+   |
+note: `UninhabitedVariants` defined here
+  --> $DIR/bad-tait-no-substs.rs:8:10
+   |
+LL | pub enum UninhabitedVariants {
+   |          ^^^^^^^^^^^^^^^^^^^
+LL |     Tuple(Alias),
+   |     ----- not covered
+   = note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~     match x {
+LL +         UninhabitedVariants::Tuple(_) => todo!(),
+LL +     }
+   |
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0004, E0106, E0107, E0792.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs
new file mode 100644
index 00000000000..8314b28eeac
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.rs
@@ -0,0 +1,22 @@
+// regression test for rust-lang/rust#125758
+
+#![feature(impl_trait_in_assoc_type)]
+
+trait Trait {
+    type Assoc2;
+}
+
+struct Bar;
+impl Trait for Bar {
+    type Assoc2 = impl std::fmt::Debug;
+    //~^ ERROR unconstrained opaque type
+}
+
+struct Foo {
+    field: <Bar as Trait>::Assoc2,
+}
+
+static BAR: u8 = 42;
+static FOO2: &Foo = unsafe { std::mem::transmute(&BAR) };
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr
new file mode 100644
index 00000000000..6cbf6c83ff4
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/bad-transmute-itiat.stderr
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/bad-transmute-itiat.rs:11:19
+   |
+LL |     type Assoc2 = impl std::fmt::Debug;
+   |                   ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Assoc2` must be used in combination with a concrete type within the same impl
+
+error: aborting due to 1 previous error
+
diff --git a/tests/crashes/130956.rs b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.rs
index ebb986d123f..4332f1264a8 100644
--- a/tests/crashes/130956.rs
+++ b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.rs
@@ -1,8 +1,11 @@
-//@ known-bug: #130956
+// Regression test for #130956
+
+#![feature(type_alias_impl_trait)]
 
 mod impl_trait_mod {
     use super::*;
     pub type OpaqueBlock = impl Trait;
+    //~^ ERROR unconstrained opaque type
     pub type OpaqueIf = impl Trait;
 
     pub struct BlockWrapper(OpaqueBlock);
diff --git a/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr
new file mode 100644
index 00000000000..8e5838d5ddf
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/drop-analysis-on-unconstrained-tait.stderr
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/drop-analysis-on-unconstrained-tait.rs:7:28
+   |
+LL |     pub type OpaqueBlock = impl Trait;
+   |                            ^^^^^^^^^^
+   |
+   = note: `OpaqueBlock` must be used in combination with a concrete type within the same module
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
index 799e8071d02..891021e8766 100644
--- a/tests/ui/unpretty/expanded-exhaustive.rs
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Zunpretty=expanded -Zunstable-options
+//@ compile-flags: -Zunpretty=expanded
 //@ edition:2024
 //@ check-pass
 
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
index d8384951e12..007626e2c44 100644
--- a/tests/ui/unpretty/expanded-exhaustive.stdout
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -1,5 +1,5 @@
 #![feature(prelude_import)]
-//@ compile-flags: -Zunpretty=expanded -Zunstable-options
+//@ compile-flags: -Zunpretty=expanded
 //@ edition:2024
 //@ check-pass
 
diff --git a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.rs b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.rs
index f12c38939dd..2fb73d3a1fa 100644
--- a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.rs
+++ b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ check-pass
 #![crate_type = "lib"]
 #![deny(unused_unsafe)]
diff --git a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
index fe12dd72d9e..321d0ca2936 100644
--- a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
+++ b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr
@@ -1,5 +1,5 @@
 warning[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block
-  --> $DIR/edition-2024-unsafe_op_in_unsafe_fn.rs:10:5
+  --> $DIR/edition-2024-unsafe_op_in_unsafe_fn.rs:9:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
@@ -7,7 +7,7 @@ LL |     unsf();
    = note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668>
    = note: consult the function's documentation for information on how to avoid undefined behavior
 note: an unsafe function restricts its caller, but its body is safe by default
-  --> $DIR/edition-2024-unsafe_op_in_unsafe_fn.rs:9:1
+  --> $DIR/edition-2024-unsafe_op_in_unsafe_fn.rs:8:1
    |
 LL | unsafe fn foo() {
    | ^^^^^^^^^^^^^^^
diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs
index 06a46b9812d..261427d1eab 100644
--- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs
+++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.rs
@@ -1,5 +1,4 @@
 //@ edition: 2024
-//@ compile-flags: -Zunstable-options
 //@ check-pass
 
 // Tests that `unsafe_op_in_unsafe_fn` is warn-by-default in edition 2024 and that the
diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
index 05f36ab47cb..d91b76e7937 100644
--- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
+++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr
@@ -1,5 +1,5 @@
 warning[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block
-  --> $DIR/edition_2024_default.rs:13:5
+  --> $DIR/edition_2024_default.rs:12:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
@@ -7,7 +7,7 @@ LL |     unsf();
    = note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668>
    = note: consult the function's documentation for information on how to avoid undefined behavior
 note: an unsafe function restricts its caller, but its body is safe by default
-  --> $DIR/edition_2024_default.rs:12:1
+  --> $DIR/edition_2024_default.rs:11:1
    |
 LL | unsafe fn foo() {
    | ^^^^^^^^^^^^^^^
diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
index e6d4e2ee01a..0be5127dcc4 100644
--- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
+++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
@@ -14,5 +14,4 @@ impl Trait for Ref {} //~ ERROR:  implicit elided lifetime not allowed here
 
 extern "C" {
     pub fn repro(_: Wrapper<Ref>);
-    //~^ ERROR the trait bound `Ref<'_>: Trait` is not satisfied
 }
diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
index 59b55b2732d..0af4ab022e1 100644
--- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
+++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
@@ -9,19 +9,6 @@ help: indicate the anonymous lifetime
 LL | impl Trait for Ref<'_> {}
    |                   ++++
 
-error[E0277]: the trait bound `Ref<'_>: Trait` is not satisfied
-  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
-   |
-LL |     pub fn repro(_: Wrapper<Ref>);
-   |                     ^^^^^^^^^^^^ the trait `Trait` is not implemented for `Ref<'_>`
-   |
-note: required by a bound in `Wrapper`
-  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:8:23
-   |
-LL | pub struct Wrapper<T: Trait>(T);
-   |                       ^^^^^ required by this bound in `Wrapper`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0277, E0726.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0726`.
diff --git a/triagebot.toml b/triagebot.toml
index 2483bfc4a41..b7a9b794c8b 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -451,7 +451,6 @@ new_issue = true
 exclude_labels = [
     "C-tracking-issue",
     "A-diagnostics",
-    "relnotes-tracking-issue",
 ]
 
 [autolabel."WG-trait-system-refactor"]