about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ghcr.yml4
-rw-r--r--.github/workflows/spellcheck.yml23
-rw-r--r--Cargo.lock206
-rw-r--r--REUSE.toml1
-rw-r--r--bootstrap.example.toml9
-rw-r--r--compiler/rustc_ast/src/ast.rs16
-rw-r--r--compiler/rustc_ast/src/visit.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs1
-rw-r--r--compiler/rustc_ast_passes/messages.ftl2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs7
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/cfg.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs101
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs33
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/loop_match.rs26
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs68
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/semantics.rs20
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs18
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs29
-rw-r--r--compiler/rustc_builtin_macros/src/autodiff.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs2
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs94
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs149
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs44
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs41
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs61
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs2
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs100
-rw-r--r--compiler/rustc_data_structures/src/vec_cache.rs2
-rw-r--r--compiler/rustc_errors/src/markdown/parse.rs2
-rw-r--r--compiler/rustc_expand/src/base.rs2
-rw-r--r--compiler/rustc_expand/src/build.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs36
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs23
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs206
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs2
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs2
-rw-r--r--compiler/rustc_lexer/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/autorefs.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs2
-rw-r--r--compiler/rustc_lint/src/default_could_be_derived.rs2
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs2
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs2
-rw-r--r--compiler/rustc_lint/src/unused.rs128
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs2
-rw-r--r--compiler/rustc_macros/src/lib.rs2
-rw-r--r--compiler/rustc_macros/src/query.rs5
-rw-r--r--compiler/rustc_metadata/src/creader.rs109
-rw-r--r--compiler/rustc_metadata/src/locator.rs124
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs9
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs10
-rw-r--r--compiler/rustc_middle/src/thir.rs14
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs6
-rw-r--r--compiler/rustc_middle/src/ty/significant_drop_order.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/into.rs12
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs6
-rw-r--r--compiler/rustc_mir_build/src/errors.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs19
-rw-r--r--compiler/rustc_mir_transform/src/check_enums.rs34
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs2
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs6
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs2
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs20
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs2
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs7
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs53
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs2
-rw-r--r--compiler/rustc_passes/messages.ftl2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs58
-rw-r--r--compiler/rustc_passes/src/dead.rs2
-rw-r--r--compiler/rustc_passes/src/errors.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs4
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs1
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs2
-rw-r--r--compiler/rustc_resolve/messages.ftl1
-rw-r--r--compiler/rustc_resolve/src/errors.rs11
-rw-r--r--compiler/rustc_resolve/src/late.rs8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs1
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs2
-rw-r--r--compiler/rustc_serialize/src/serialize.rs2
-rw-r--r--compiler/rustc_session/src/config.rs2
-rw-r--r--compiler/rustc_session/src/session.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs6
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs2
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/callconv/s390x.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs71
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs7
-rw-r--r--compiler/rustc_traits/src/codegen.rs11
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs58
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs2
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs2
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs6
-rw-r--r--library/alloc/src/boxed.rs229
-rw-r--r--library/alloc/src/rc.rs122
-rw-r--r--library/alloc/src/sync.rs122
-rw-r--r--library/alloc/src/vec/mod.rs219
-rw-r--r--library/core/src/bool.rs67
-rw-r--r--library/core/src/cmp.rs4
-rw-r--r--library/core/src/error.rs2
-rw-r--r--library/core/src/ffi/c_char.md2
-rw-r--r--library/core/src/fmt/mod.rs7
-rw-r--r--library/core/src/fmt/num.rs2
-rw-r--r--library/core/src/hash/mod.rs7
-rw-r--r--library/core/src/intrinsics/mod.rs17
-rw-r--r--library/core/src/intrinsics/simd.rs4
-rw-r--r--library/core/src/io/borrowed_buf.rs2
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/marker.rs3
-rw-r--r--library/core/src/mem/maybe_uninit.rs4
-rw-r--r--library/core/src/num/dec2flt/float.rs6
-rw-r--r--library/core/src/num/error.rs2
-rw-r--r--library/core/src/num/uint_macros.rs2
-rw-r--r--library/core/src/ops/range.rs2
-rw-r--r--library/core/src/pin.rs2
-rw-r--r--library/core/src/ptr/const_ptr.rs4
-rw-r--r--library/core/src/ptr/mut_ptr.rs2
-rw-r--r--library/core/src/ptr/non_null.rs2
-rw-r--r--library/core/src/tuple.rs18
-rw-r--r--library/coretests/tests/bool.rs8
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/coretests/tests/num/dec2flt/float.rs4
-rw-r--r--library/rustc-std-workspace-core/Cargo.toml8
-rw-r--r--library/std/src/fs.rs52
-rw-r--r--library/std/src/os/unix/process.rs2
-rw-r--r--library/std/src/path.rs6
-rw-r--r--library/std/src/sys/net/connection/socket/wasip2.rs2
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs6
-rw-r--r--library/std/src/sys/path/cygwin.rs2
-rw-r--r--library/std/src/sys/random/linux.rs4
-rw-r--r--library/std/src/sys/random/unsupported.rs2
-rw-r--r--library/std/src/thread/spawnhook.rs2
-rw-r--r--library/std/src/time.rs6
-rw-r--r--library/std/tests/thread_local/tests.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs26
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs12
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs1
-rw-r--r--src/bootstrap/src/core/builder/mod.rs12
-rw-r--r--src/bootstrap/src/core/builder/tests.rs385
-rw-r--r--src/bootstrap/src/core/config/config.rs5
-rw-r--r--src/bootstrap/src/core/config/flags.rs2
-rw-r--r--src/bootstrap/src/core/config/toml/build.rs1
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs43
-rw-r--r--src/bootstrap/src/core/config/toml/target.rs22
-rw-r--r--src/bootstrap/src/utils/cache/tests.rs11
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs9
-rw-r--r--src/bootstrap/src/utils/proc_macro_deps.rs1
-rw-r--r--src/ci/citool/src/jobs.rs9
-rw-r--r--src/ci/citool/src/jobs/tests.rs26
-rw-r--r--src/ci/citool/tests/jobs.rs2
-rw-r--r--src/ci/citool/tests/test-jobs.yml11
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-1/Dockerfile58
-rw-r--r--src/ci/docker/host-x86_64/pr-check-1/Dockerfile58
-rwxr-xr-xsrc/ci/docker/host-x86_64/pr-check-1/check-default-config-profiles.sh (renamed from src/ci/docker/host-x86_64/mingw-check-1/check-default-config-profiles.sh)0
-rw-r--r--src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.in (renamed from src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.in)0
-rw-r--r--src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.txt (renamed from src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.txt)0
-rwxr-xr-xsrc/ci/docker/host-x86_64/pr-check-1/validate-toolstate.sh (renamed from src/ci/docker/host-x86_64/mingw-check-1/validate-toolstate.sh)0
-rw-r--r--src/ci/docker/host-x86_64/pr-check-2/Dockerfile (renamed from src/ci/docker/host-x86_64/mingw-check-2/Dockerfile)0
-rw-r--r--src/ci/docker/host-x86_64/tidy/Dockerfile (renamed from src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile)12
-rw-r--r--src/ci/docker/host-x86_64/tidy/eslint.version (renamed from src/ci/docker/host-x86_64/mingw-check-tidy/eslint.version)0
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/ci/github-actions/jobs.yml23
-rw-r--r--src/doc/rustc-dev-guide/src/solve/opaque-types.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ci.md11
-rw-r--r--src/doc/rustc-dev-guide/src/tests/minicore.md6
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/etc/completions/x.py.fish2
-rw-r--r--src/etc/completions/x.py.ps12
-rw-r--r--src/etc/completions/x.py.zsh2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/mod.rs24
-rw-r--r--src/librustdoc/clean/types.rs29
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/doctest.rs2
-rw-r--r--src/librustdoc/doctest/extracted.rs2
-rw-r--r--src/librustdoc/externalfiles.rs26
-rw-r--r--src/librustdoc/html/markdown.rs31
-rw-r--r--src/librustdoc/html/markdown/footnotes.rs4
-rw-r--r--src/librustdoc/html/markdown/tests.rs21
-rw-r--r--src/librustdoc/html/render/mod.rs37
-rw-r--r--src/librustdoc/html/render/write_shared.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css98
-rw-r--r--src/librustdoc/html/static/js/main.js2
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts2
-rw-r--r--src/librustdoc/markdown.rs56
-rw-r--r--src/librustdoc/passes/strip_aliased_non_local.rs2
-rw-r--r--src/librustdoc/passes/strip_hidden.rs2
-rw-r--r--src/librustdoc/visit_ast.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs7
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics-clippy.rs22
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr29
-rw-r--r--src/tools/compiletest/src/directive-list.rs2
-rw-r--r--src/tools/compiletest/src/directives.rs (renamed from src/tools/compiletest/src/header.rs)41
-rw-r--r--src/tools/compiletest/src/directives/auxiliary.rs (renamed from src/tools/compiletest/src/header/auxiliary.rs)2
-rw-r--r--src/tools/compiletest/src/directives/cfg.rs (renamed from src/tools/compiletest/src/header/cfg.rs)2
-rw-r--r--src/tools/compiletest/src/directives/needs.rs (renamed from src/tools/compiletest/src/header/needs.rs)2
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs (renamed from src/tools/compiletest/src/header/test-auxillary/error_annotation.rs)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/known_directive.rs (renamed from src/tools/compiletest/src/header/test-auxillary/known_directive.rs)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile (renamed from src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile)0
-rw-r--r--src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs (renamed from src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs)0
-rw-r--r--src/tools/compiletest/src/directives/tests.rs (renamed from src/tools/compiletest/src/header/tests.rs)8
-rw-r--r--src/tools/compiletest/src/lib.rs14
-rw-r--r--src/tools/compiletest/src/runtest.rs4
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs6
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs4
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs15
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs4
-rw-r--r--src/tools/miri/src/shims/backtrace.rs2
-rw-r--r--src/tools/miri/src/shims/native_lib/mod.rs41
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr6
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr28
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs8
-rw-r--r--src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr28
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_float.stderr2
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_integer.stderr2
-rw-r--r--src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr2
-rw-r--r--src/tools/rustbook/Cargo.lock156
-rw-r--r--src/tools/rustdoc-gui-test/src/main.rs2
-rw-r--r--src/tools/rustdoc-gui/tester.js2
-rw-r--r--src/tools/rustfmt/tests/source/let_chains.rs2
-rw-r--r--src/tools/rustfmt/tests/target/let_chains.rs2
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs53
-rw-r--r--src/tools/tidy/src/rustdoc_js.rs3
-rw-r--r--tests/auxiliary/minicore.rs20
-rw-r--r--tests/codegen/transmute-scalar.rs55
-rw-r--r--tests/coverage/branch/if-let.coverage4
-rw-r--r--tests/coverage/branch/if-let.rs4
-rw-r--r--tests/mir-opt/inline_var_debug_info_kept.rs50
-rw-r--r--tests/rustdoc-gui/docblock-code-block-line-number.goml4
-rw-r--r--tests/rustdoc-gui/scrape-examples-button-focus.goml2
-rw-r--r--tests/rustdoc-gui/source-code-wrapping.goml29
-rw-r--r--tests/rustdoc-json/attrs/target_feature.rs17
-rw-r--r--tests/rustdoc/attributes-re-export.rs13
-rw-r--r--tests/rustdoc/reexport/extern-135092.rs26
-rw-r--r--tests/ui/abi/bad-custom.stderr2
-rw-r--r--tests/ui/abi/cannot-be-coroutine.avr.stderr2
-rw-r--r--tests/ui/abi/cannot-be-coroutine.i686.stderr2
-rw-r--r--tests/ui/abi/cannot-be-coroutine.msp430.stderr2
-rw-r--r--tests/ui/abi/cannot-be-coroutine.riscv32.stderr4
-rw-r--r--tests/ui/abi/cannot-be-coroutine.riscv64.stderr4
-rw-r--r--tests/ui/abi/cannot-be-coroutine.x64.stderr2
-rw-r--r--tests/ui/abi/cannot-be-coroutine.x64_win.stderr2
-rw-r--r--tests/ui/abi/debug.rs16
-rw-r--r--tests/ui/abi/debug.stderr30
-rw-r--r--tests/ui/abi/rust-cold-works-with-rustic-args.rs13
-rw-r--r--tests/ui/attributes/crate-type-macro-empty.rs2
-rw-r--r--tests/ui/attributes/crate-type-macro-empty.stderr4
-rw-r--r--tests/ui/attributes/malformed-attrs.rs1
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr171
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/drop/drop-order-comparisons-let-chains.rs145
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.fixed114
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.stderr96
-rw-r--r--tests/ui/drop/drop-order-comparisons.rs114
-rw-r--r--tests/ui/drop/drop_order.rs74
-rw-r--r--tests/ui/drop/drop_order_let_chain.rs103
-rw-r--r--tests/ui/drop/issue-100276.rs9
-rw-r--r--tests/ui/error-codes/E0637.stderr2
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr16
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.fixed87
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.rs87
-rw-r--r--tests/ui/lint/lint-unnecessary-parens.stderr210
-rw-r--r--tests/ui/lint/unused/issue-105061-should-lint.rs2
-rw-r--r--tests/ui/lint/unused/issue-105061-should-lint.stderr10
-rw-r--r--tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed27
-rw-r--r--tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr19
-rw-r--r--tests/ui/lint/unused/unused-parens-trait-obj.rs27
-rw-r--r--tests/ui/loop-match/invalid.rs31
-rw-r--r--tests/ui/loop-match/invalid.stderr34
-rw-r--r--tests/ui/macros/missing-semi.stderr4
-rw-r--r--tests/ui/macros/stringify.rs3
-rw-r--r--tests/ui/mir/enum/negative_discr_break.rs14
-rw-r--r--tests/ui/mir/enum/negative_discr_ok.rs53
-rw-r--r--tests/ui/mir/mir_let_chains_drop_order.rs11
-rw-r--r--tests/ui/parser/issues/issue-7970b.rs2
-rw-r--r--tests/ui/parser/issues/issue-7970b.stderr4
-rw-r--r--tests/ui/parser/macros-no-semicolon-items.rs2
-rw-r--r--tests/ui/parser/macros-no-semicolon-items.stderr4
-rw-r--r--tests/ui/pattern/usefulness/conflicting_bindings.rs4
-rw-r--r--tests/ui/pattern/usefulness/conflicting_bindings.stderr18
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope-let-chains.rs57
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs45
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs1
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs1
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr (renamed from tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr)450
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr (renamed from tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr)304
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr264
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs67
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr35
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr23
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs12
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.rs (renamed from tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs)20
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.stderr81
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr114
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr38
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs11
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs3
-rw-r--r--tests/ui/sanitizer/cfi/closures.rs4
-rw-r--r--tests/ui/target-feature/invalid-attribute.rs8
-rw-r--r--tests/ui/target-feature/invalid-attribute.stderr85
-rw-r--r--tests/ui/thir-print/thir-tree-loop-match.stdout290
-rw-r--r--tests/ui/traits/const-traits/const-via-item-bound.rs19
-rw-r--r--tests/ui/traits/dyn-trait.rs2
-rw-r--r--tests/ui/traits/impl-2.rs2
-rw-r--r--tests/ui/traits/negative-bounds/negative-sized.rs8
-rw-r--r--tests/ui/traits/negative-bounds/negative-sized.stderr15
-rw-r--r--tests/ui/typeck/auxiliary/private-dep.rs3
-rw-r--r--tests/ui/typeck/auxiliary/public-dep.rs11
-rw-r--r--tests/ui/typeck/dont-suggest-private-dependencies.rs37
-rw-r--r--tests/ui/typeck/dont-suggest-private-dependencies.stderr27
-rw-r--r--tests/ui/underscore-lifetime/in-binder.stderr12
-rw-r--r--tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr4
-rw-r--r--triagebot.toml109
-rw-r--r--typos.toml74
384 files changed, 5487 insertions, 3609 deletions
diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml
index c2c0c11f008..6d050d98cb2 100644
--- a/.github/workflows/ghcr.yml
+++ b/.github/workflows/ghcr.yml
@@ -53,9 +53,9 @@ jobs:
         run: |
           # List of DockerHub images to mirror to ghcr.io
           images=(
-            # Mirrored because used by the mingw-check-tidy, which doesn't cache Docker images
+            # Mirrored because used by the tidy job, which doesn't cache Docker images
             "ubuntu:22.04"
-            # Mirrored because used by all linux CI jobs, including mingw-check-tidy
+            # Mirrored because used by all linux CI jobs, including tidy
             "moby/buildkit:buildx-stable-1"
             # Mirrored because used when CI is running inside a Docker container
             "alpine:3.4"
diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml
new file mode 100644
index 00000000000..7e21bb1b7ff
--- /dev/null
+++ b/.github/workflows/spellcheck.yml
@@ -0,0 +1,23 @@
+# This workflow runs spellcheck job
+
+name: Spellcheck
+on:
+  pull_request:
+    branches:
+      - "**"
+
+jobs:
+  spellcheck:
+    name: run spellchecker
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout the source code
+        uses: actions/checkout@v4
+
+      - name: check typos
+        # sync version with src/tools/tidy/src/ext_tool_checks.rs in spellcheck_runner
+        uses: crate-ci/typos@v1.34.0
+        with:
+          # sync target files with src/tools/tidy/src/ext_tool_checks.rs in check_impl
+          files: ./compiler ./library ./src/bootstrap ./src/librustdoc
+          config: ./typos.toml
diff --git a/Cargo.lock b/Cargo.lock
index da3eb92ece8..7cf10628b00 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,9 +128,9 @@ dependencies = [
 
 [[package]]
 name = "anstyle-svg"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a"
+checksum = "0a43964079ef399480603125d5afae2b219aceffb77478956e25f17b9bc3435c"
 dependencies = [
  "anstyle",
  "anstyle-lossy",
@@ -204,7 +204,7 @@ dependencies = [
  "rustc-hash 2.1.1",
  "serde",
  "serde_derive",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -221,9 +221,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
 
 [[package]]
 name = "backtrace"
@@ -341,9 +341,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.18.1"
+version = "3.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
 
 [[package]]
 name = "bytecount"
@@ -546,7 +546,7 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -579,7 +579,7 @@ dependencies = [
  "rustc_tools_util 0.4.2",
  "serde",
  "serde_json",
- "syn 2.0.103",
+ "syn 2.0.104",
  "tempfile",
  "termize",
  "tokio",
@@ -673,7 +673,7 @@ dependencies = [
  "eyre",
  "indenter",
  "once_cell",
- "owo-colors 4.2.1",
+ "owo-colors 4.2.2",
  "tracing-error",
 ]
 
@@ -695,7 +695,7 @@ dependencies = [
  "nom",
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -705,7 +705,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427"
 dependencies = [
  "once_cell",
- "owo-colors 4.2.1",
+ "owo-colors 4.2.2",
  "tracing-core",
  "tracing-error",
 ]
@@ -922,7 +922,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -933,7 +933,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -959,13 +959,13 @@ version = "0.1.90"
 
 [[package]]
 name = "derive-where"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902"
+checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -986,7 +986,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -996,7 +996,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
 dependencies = [
  "derive_builder_core",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -1008,7 +1008,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -1098,7 +1098,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -1168,12 +1168,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.12"
+version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
 dependencies = [
  "libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -1378,7 +1378,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -1812,7 +1812,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -1878,9 +1878,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
 
 [[package]]
 name = "indexmap"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -2008,7 +2008,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -2152,9 +2152,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
 
 [[package]]
 name = "libredox"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
 dependencies = [
  "bitflags",
  "libc",
@@ -2279,7 +2279,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -2691,9 +2691,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
 
 [[package]]
 name = "owo-colors"
-version = "4.2.1"
+version = "4.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec"
+checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e"
 
 [[package]]
 name = "pad"
@@ -2770,9 +2770,9 @@ dependencies = [
 
 [[package]]
 name = "pest"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6"
+checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
 dependencies = [
  "memchr",
  "thiserror 2.0.12",
@@ -2781,9 +2781,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5"
+checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
 dependencies = [
  "pest",
  "pest_generator",
@@ -2791,24 +2791,23 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841"
+checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
 dependencies = [
  "pest",
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
 name = "pest_meta"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0"
+checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
 dependencies = [
- "once_cell",
  "pest",
  "sha2",
 ]
@@ -2994,9 +2993,9 @@ dependencies = [
 
 [[package]]
 name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
 
 [[package]]
 name = "rand"
@@ -3218,14 +3217,14 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.8"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16d115ad7e26e0d1337f64ae6598f758194696afc2e9f34c8a6f24582529c3dc"
+checksum = "fdb13874a0e55baf4ac3d49d38206aecb31a55b75d6c4d04fd850b53942c8cc8"
 dependencies = [
  "anyhow",
- "regex",
  "rustc_version",
  "tempfile",
+ "toml 0.8.23",
  "walkdir",
 ]
 
@@ -3814,7 +3813,7 @@ dependencies = [
  "fluent-syntax",
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "unic-langid",
 ]
 
@@ -3963,7 +3962,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -4110,7 +4109,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "synstructure",
 ]
 
@@ -4629,6 +4628,7 @@ dependencies = [
  "itertools",
  "rustc_abi",
  "rustc_ast",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
@@ -4722,7 +4722,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "synstructure",
 ]
 
@@ -4813,7 +4813,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -4950,7 +4950,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -5025,12 +5025,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
 
 [[package]]
 name = "slab"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-dependencies = [
- "autocfg",
-]
+checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
 
 [[package]]
 name = "smallvec"
@@ -5190,9 +5187,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.103"
+version = "2.0.104"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5207,7 +5204,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -5340,7 +5337,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -5351,7 +5348,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -5481,7 +5478,20 @@ dependencies = [
  "serde",
  "serde_spanned",
  "toml_datetime",
- "toml_edit",
+ "toml_edit 0.19.15",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit 0.22.27",
 ]
 
 [[package]]
@@ -5507,6 +5517,26 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_edit"
+version = "0.22.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_write",
+ "winnow 0.7.11",
+]
+
+[[package]]
+name = "toml_write"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
+
+[[package]]
 name = "tracing"
 version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5520,13 +5550,13 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.29"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662"
+checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -5703,7 +5733,7 @@ checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5"
 dependencies = [
  "proc-macro-hack",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "unic-langid-impl",
 ]
 
@@ -5915,7 +5945,7 @@ dependencies = [
  "log",
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "wasm-bindgen-shared",
 ]
 
@@ -5937,7 +5967,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -6205,7 +6235,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -6216,7 +6246,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -6227,7 +6257,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -6238,7 +6268,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -6612,9 +6642,9 @@ version = "0.1.1"
 
 [[package]]
 name = "xattr"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
+checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909"
 dependencies = [
  "libc",
  "rustix",
@@ -6670,7 +6700,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "synstructure",
 ]
 
@@ -6682,28 +6712,28 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "synstructure",
 ]
 
 [[package]]
 name = "zerocopy"
-version = "0.8.25"
+version = "0.8.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.8.25"
+version = "0.8.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -6723,7 +6753,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
  "synstructure",
 ]
 
@@ -6768,7 +6798,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
 
 [[package]]
@@ -6779,5 +6809,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.103",
+ "syn 2.0.104",
 ]
diff --git a/REUSE.toml b/REUSE.toml
index 816c6d730c8..027b4ccbe25 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -36,6 +36,7 @@ path = [
     "rustfmt.toml",
     "rust-bors.toml",
     "triagebot.toml",
+    "typos.toml",
     "x",
     "x.ps1",
     "x.py",
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index cc1ea796a02..b59f112bdfb 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -467,6 +467,15 @@
 # Whether to use the precompiled stage0 libtest with compiletest.
 #build.compiletest-use-stage0-libtest = true
 
+# Default value for the `--extra-checks` flag of tidy.
+#
+# See `./x test tidy --help` for details.
+#
+# Note that if any value is manually given to bootstrap such as
+# `./x test tidy --extra-checks=js`, this value is ignored.
+# Use `--extra-checks=''` to temporarily disable all extra checks.
+#build.tidy-extra-checks = ""
+
 # Indicates whether ccache is used when building certain artifacts (e.g. LLVM).
 # Set to `true` to use the first `ccache` in PATH, or set an absolute path to use
 # a specific version.
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 286bbfb5ae8..ac6daba3901 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1344,7 +1344,7 @@ impl Expr {
         }
     }
 
-    /// Returns an expression with (when possible) *one* outter brace removed
+    /// Returns an expression with (when possible) *one* outer brace removed
     pub fn maybe_unwrap_block(&self) -> &Expr {
         if let ExprKind::Block(block, None) = &self.kind
             && let [stmt] = block.stmts.as_slice()
@@ -1390,6 +1390,7 @@ impl Expr {
                 path.clone(),
                 TraitBoundModifiers::NONE,
                 self.span,
+                Parens::No,
             ))),
             _ => None,
         }
@@ -3366,6 +3367,13 @@ pub struct TraitRef {
     pub ref_id: NodeId,
 }
 
+/// Whether enclosing parentheses are present or not.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum Parens {
+    Yes,
+    No,
+}
+
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct PolyTraitRef {
     /// The `'a` in `for<'a> Foo<&'a T>`.
@@ -3378,6 +3386,10 @@ pub struct PolyTraitRef {
     pub trait_ref: TraitRef,
 
     pub span: Span,
+
+    /// When `Yes`, the first and last character of `span` are an opening
+    /// and a closing paren respectively.
+    pub parens: Parens,
 }
 
 impl PolyTraitRef {
@@ -3386,12 +3398,14 @@ impl PolyTraitRef {
         path: Path,
         modifiers: TraitBoundModifiers,
         span: Span,
+        parens: Parens,
     ) -> Self {
         PolyTraitRef {
             bound_generic_params: generic_params,
             modifiers,
             trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID },
             span,
+            parens,
         }
     }
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index d0c2b2bf68b..42de5b727c5 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -142,7 +142,7 @@ macro_rules! common_visitor_and_walkers {
             )?
 
             // Methods in this trait have one of three forms, with the last two forms
-            // only occuring on `MutVisitor`:
+            // only occurring on `MutVisitor`:
             //
             //   fn visit_t(&mut self, t: &mut T);                      // common
             //   fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>;    // rare
@@ -1142,7 +1142,7 @@ macro_rules! common_visitor_and_walkers {
             vis: &mut V,
             p: &$($lt)? $($mut)? PolyTraitRef,
         ) -> V::Result {
-            let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p;
+            let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ } = p;
             try_visit!(visit_modifiers(vis, modifiers));
             try_visit!(visit_generic_params(vis, bound_generic_params));
             try_visit!(vis.visit_trait_ref(trait_ref));
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 8acb5105773..bdcb750ba26 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -2,6 +2,7 @@ use rustc_abi::ExternAbi;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
 use rustc_ast::*;
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::def::{DefKind, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
@@ -1621,7 +1622,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let safety = self.lower_safety(h.safety, default_safety);
 
         // Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
-        let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature))
+        let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. })
             && safety.is_safe()
             && !self.tcx.sess.target.is_like_wasm
         {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 26d7c0cd6d3..d14e27982ef 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1209,6 +1209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         modifiers: TraitBoundModifiers::NONE,
                         trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
                         span: t.span,
+                        parens: ast::Parens::No,
                     },
                     itctx,
                 );
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 4290f7b7ede..d58c140c696 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -1,6 +1,6 @@
 ast_passes_abi_cannot_be_coroutine =
     functions with the {$abi} ABI cannot be `{$coroutine_kind_str}`
-    .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
+    .suggestion = remove the `{$coroutine_kind_str}` keyword from this definition
 
 ast_passes_abi_custom_safe_foreign_function =
     foreign functions with the "custom" ABI cannot be safe
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index c7f41fc3cb1..5d8ee07178d 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -469,7 +469,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
         "`if let` guards are experimental",
         "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
     );
-    gate_all!(let_chains, "`let` expressions in this position are unstable");
     gate_all!(
         async_trait_bounds,
         "`async` trait bounds are unstable",
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 6f4cc83fd10..61ef31b8f9f 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -198,10 +198,10 @@ pub enum AttributeKind {
     Align { align: Align, span: Span },
 
     /// Represents `#[rustc_allow_const_fn_unstable]`.
-    AllowConstFnUnstable(ThinVec<Symbol>),
+    AllowConstFnUnstable(ThinVec<Symbol>, Span),
 
     /// Represents `#[allow_internal_unstable]`.
-    AllowInternalUnstable(ThinVec<(Symbol, Span)>),
+    AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
 
     /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
     AsPtr(Span),
@@ -309,6 +309,9 @@ pub enum AttributeKind {
         span: Span,
     },
 
+    /// Represents `#[target_feature(enable = "...")]`
+    TargetFeature(ThinVec<(Symbol, Span)>, Span),
+
     /// Represents `#[track_caller]`
     TrackCaller(Span),
 
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index 58ced8e3281..a1b1d670cfe 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -42,6 +42,7 @@ impl AttributeKind {
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcObjectLifetimeDefault => No,
             SkipDuringMethodDispatch { .. } => No,
+            TargetFeature(..) => No,
             TrackCaller(..) => Yes,
             Used { .. } => No,
         }
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 21b01a8d071..1c51c3eee4e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -13,7 +13,8 @@ pub(crate) struct AllowInternalUnstableParser;
 impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
     const PATH: &[Symbol] = &[sym::allow_internal_unstable];
     type Item = (Symbol, Span);
-    const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
+    const CONVERT: ConvertFn<Self::Item> =
+        |items, span| AttributeKind::AllowInternalUnstable(items, span);
     const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
 
     fn extend<'c>(
@@ -30,7 +31,8 @@ pub(crate) struct AllowConstFnUnstableParser;
 impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
     const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
     type Item = Symbol;
-    const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
+    const CONVERT: ConvertFn<Self::Item> =
+        |items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
     const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
 
     fn extend<'c>(
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index f4d23012af7..a8d9229cbc3 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -14,7 +14,7 @@ use crate::{fluent_generated, parse_version};
 
 /// Emitter of a builtin lint from `cfg_matches`.
 ///
-/// Used to support emiting a lint (currently on check-cfg), either:
+/// Used to support emitting a lint (currently on check-cfg), either:
 ///  - as an early buffered lint (in `rustc`)
 ///  - or has a "normal" lint from HIR (in `rustdoc`)
 pub trait CfgMatchesLintEmitter {
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index 7c412d4fa89..13f560dff38 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -3,7 +3,10 @@ use rustc_feature::{AttributeTemplate, template};
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
 
-use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
+use super::{
+    AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn,
+    NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
+};
 use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
@@ -43,20 +46,10 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
 
 pub(crate) struct ColdParser;
 
-impl<S: Stage> SingleAttributeParser<S> for ColdParser {
+impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
     const PATH: &[Symbol] = &[sym::cold];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.expected_no_args(span);
-            return None;
-        }
-
-        Some(AttributeKind::Cold(cx.attr_span))
-    }
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
 }
 
 pub(crate) struct ExportNameParser;
@@ -194,39 +187,17 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
 }
 
 pub(crate) struct TrackCallerParser;
-
-impl<S: Stage> SingleAttributeParser<S> for TrackCallerParser {
+impl<S: Stage> NoArgsAttributeParser<S> for TrackCallerParser {
     const PATH: &[Symbol] = &[sym::track_caller];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.expected_no_args(span);
-            return None;
-        }
-
-        Some(AttributeKind::TrackCaller(cx.attr_span))
-    }
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
 }
 
 pub(crate) struct NoMangleParser;
-
-impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
-    const PATH: &[rustc_span::Symbol] = &[sym::no_mangle];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
+impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
+    const PATH: &[Symbol] = &[sym::no_mangle];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.expected_no_args(span);
-            return None;
-        }
-
-        Some(AttributeKind::NoMangle(cx.attr_span))
-    }
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
 }
 
 #[derive(Default)]
@@ -309,3 +280,53 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
         })
     }
 }
+
+pub(crate) struct TargetFeatureParser;
+
+impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
+    type Item = (Symbol, Span);
+    const PATH: &[Symbol] = &[sym::target_feature];
+    const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
+    const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
+
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'c {
+        let mut features = Vec::new();
+        let ArgParser::List(list) = args else {
+            cx.expected_list(cx.attr_span);
+            return features;
+        };
+        for item in list.mixed() {
+            let Some(name_value) = item.meta_item() else {
+                cx.expected_name_value(item.span(), Some(sym::enable));
+                return features;
+            };
+
+            // Validate name
+            let Some(name) = name_value.path().word_sym() else {
+                cx.expected_name_value(name_value.path().span(), Some(sym::enable));
+                return features;
+            };
+            if name != sym::enable {
+                cx.expected_name_value(name_value.path().span(), Some(sym::enable));
+                return features;
+            }
+
+            // Use value
+            let Some(name_value) = name_value.args().name_value() else {
+                cx.expected_name_value(item.span(), Some(sym::enable));
+                return features;
+            };
+            let Some(value_str) = name_value.value_as_str() else {
+                cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
+                return features;
+            };
+            for feature in value_str.as_str().split(",") {
+                features.push((Symbol::intern(feature), item.span()));
+            }
+        }
+        features
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
index 1c8fc5079da..5437803d781 100644
--- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -1,38 +1,19 @@
 use rustc_attr_data_structures::AttributeKind;
-use rustc_feature::{AttributeTemplate, template};
-use rustc_span::{Symbol, sym};
+use rustc_span::{Span, Symbol, sym};
 
-use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
-use crate::parser::ArgParser;
+use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
+use crate::context::Stage;
 
 pub(crate) struct AsPtrParser;
-
-impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
+impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
     const PATH: &[Symbol] = &[sym::rustc_as_ptr];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.expected_no_args(span);
-        }
-        Some(AttributeKind::AsPtr(cx.attr_span))
-    }
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr;
 }
 
 pub(crate) struct PubTransparentParser;
-impl<S: Stage> SingleAttributeParser<S> for PubTransparentParser {
+impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
     const PATH: &[Symbol] = &[sym::rustc_pub_transparent];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.expected_no_args(span);
-        }
-        Some(AttributeKind::PubTransparent(cx.attr_span))
-    }
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
index f6c7ac5e3a3..80808b90dc6 100644
--- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs
@@ -1,31 +1,19 @@
 use rustc_attr_data_structures::AttributeKind;
-use rustc_feature::{AttributeTemplate, template};
-use rustc_span::{Symbol, sym};
+use rustc_span::{Span, Symbol, sym};
 
-use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
-use crate::parser::ArgParser;
+use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
+use crate::context::Stage;
 
 pub(crate) struct LoopMatchParser;
-impl<S: Stage> SingleAttributeParser<S> for LoopMatchParser {
+impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser {
     const PATH: &[Symbol] = &[sym::loop_match];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
-        Some(AttributeKind::LoopMatch(cx.attr_span))
-    }
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch;
 }
 
 pub(crate) struct ConstContinueParser;
-impl<S: Stage> SingleAttributeParser<S> for ConstContinueParser {
+impl<S: Stage> NoArgsAttributeParser<S> for ConstContinueParser {
     const PATH: &[Symbol] = &[sym::const_continue];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
-        Some(AttributeKind::ConstContinue(cx.attr_span))
-    }
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index b3a9c69c055..0215504b52b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -17,7 +17,7 @@
 use std::marker::PhantomData;
 
 use rustc_attr_data_structures::AttributeKind;
-use rustc_feature::AttributeTemplate;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
 
@@ -229,7 +229,42 @@ pub(crate) enum AttributeOrder {
     KeepLast,
 }
 
-type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
+/// An even simpler version of [`SingleAttributeParser`]:
+/// now automatically check that there are no arguments provided to the attribute.
+///
+/// [`WithoutArgs<T> where T: NoArgsAttributeParser`](WithoutArgs) implements [`SingleAttributeParser`].
+//
+pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
+    const PATH: &[Symbol];
+    const ON_DUPLICATE: OnDuplicate<S>;
+
+    /// Create the [`AttributeKind`] given attribute's [`Span`].
+    const CREATE: fn(Span) -> AttributeKind;
+}
+
+pub(crate) struct WithoutArgs<T: NoArgsAttributeParser<S>, S: Stage>(PhantomData<(S, T)>);
+
+impl<T: NoArgsAttributeParser<S>, S: Stage> Default for WithoutArgs<T, S> {
+    fn default() -> Self {
+        Self(Default::default())
+    }
+}
+
+impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> {
+    const PATH: &[Symbol] = T::PATH;
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
+    const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
+    const TEMPLATE: AttributeTemplate = template!(Word);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        if let Err(span) = args.no_args() {
+            cx.expected_no_args(span);
+        }
+        Some(T::CREATE(cx.attr_span))
+    }
+}
+
+type ConvertFn<E> = fn(ThinVec<E>, Span) -> AttributeKind;
 
 /// Alternative to [`AttributeParser`] that automatically handles state management.
 /// If multiple attributes appear on an element, combines the values of each into a
@@ -260,14 +295,21 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
 
 /// Use in combination with [`CombineAttributeParser`].
 /// `Combine<T: CombineAttributeParser>` implements [`AttributeParser`].
-pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
-    PhantomData<(S, T)>,
-    ThinVec<<T as CombineAttributeParser<S>>::Item>,
-);
+pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage> {
+    phantom: PhantomData<(S, T)>,
+    /// A list of all items produced by parsing attributes so far. One attribute can produce any amount of items.
+    items: ThinVec<<T as CombineAttributeParser<S>>::Item>,
+    /// The full span of the first attribute that was encountered.
+    first_span: Option<Span>,
+}
 
 impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
     fn default() -> Self {
-        Self(Default::default(), Default::default())
+        Self {
+            phantom: Default::default(),
+            items: Default::default(),
+            first_span: Default::default(),
+        }
     }
 }
 
@@ -275,10 +317,18 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
     const ATTRIBUTES: AcceptMapping<Self, S> = &[(
         T::PATH,
         <T as CombineAttributeParser<S>>::TEMPLATE,
-        |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
+        |group: &mut Combine<T, S>, cx, args| {
+            // Keep track of the span of the first attribute, for diagnostics
+            group.first_span.get_or_insert(cx.attr_span);
+            group.items.extend(T::extend(cx, args))
+        },
     )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
-        if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
+        if let Some(first_span) = self.first_span {
+            Some(T::CONVERT(self.items, first_span))
+        } else {
+            None
+        }
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 4aa27043e98..1c070dc2685 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -23,7 +23,7 @@ pub(crate) struct ReprParser;
 impl<S: Stage> CombineAttributeParser<S> for ReprParser {
     type Item = (ReprAttr, Span);
     const PATH: &[Symbol] = &[sym::repr];
-    const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
+    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::Repr(items);
     // FIXME(jdonszelmann): never used
     const TEMPLATE: AttributeTemplate =
         template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent");
diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
index 54f50445fbd..74fdff5d2e1 100644
--- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs
@@ -1,22 +1,12 @@
 use rustc_attr_data_structures::AttributeKind;
-use rustc_feature::{AttributeTemplate, template};
-use rustc_span::{Symbol, sym};
+use rustc_span::{Span, Symbol, sym};
 
-use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
-use crate::context::{AcceptContext, Stage};
-use crate::parser::ArgParser;
+use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
+use crate::context::Stage;
 
 pub(crate) struct MayDangleParser;
-impl<S: Stage> SingleAttributeParser<S> for MayDangleParser {
+impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser {
     const PATH: &[Symbol] = &[sym::may_dangle];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.expected_no_args(span);
-        }
-        Some(AttributeKind::MayDangle(cx.attr_span))
-    }
+    const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 37104855623..6bccd0042a8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -5,11 +5,12 @@ use rustc_attr_data_structures::{
     StableSince, UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_errors::ErrorGuaranteed;
-use rustc_feature::{AttributeTemplate, template};
+use rustc_feature::template;
 use rustc_span::{Ident, Span, Symbol, sym};
 
 use super::util::parse_version;
-use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
+use super::{AcceptMapping, AttributeParser, OnDuplicate};
+use crate::attributes::NoArgsAttributeParser;
 use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::{ArgParser, MetaItemParser};
 use crate::session_diagnostics::{self, UnsupportedLiteralReason};
@@ -132,19 +133,10 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
 }
 
 pub(crate) struct ConstStabilityIndirectParser;
-// FIXME(jdonszelmann): single word attribute group when we have these
-impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
+impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser {
     const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
-    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
-    const TEMPLATE: AttributeTemplate = template!(Word);
-
-    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        if let Err(span) = args.no_args() {
-            cx.expected_no_args(span);
-        }
-        Some(AttributeKind::ConstStabilityIndirect)
-    }
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect;
 }
 
 #[derive(Default)]
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index cfba0650932..bf8b1438df7 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -16,8 +16,8 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 
 use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
 use crate::attributes::codegen_attrs::{
-    ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
-    UsedParser,
+    ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser,
+    TrackCallerParser, UsedParser,
 };
 use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
@@ -37,7 +37,7 @@ use crate::attributes::stability::{
 };
 use crate::attributes::traits::SkipDuringMethodDispatchParser;
 use crate::attributes::transparency::TransparencyParser;
-use crate::attributes::{AttributeParser as _, Combine, Single};
+use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
 use crate::parser::{ArgParser, MetaItemParser, PathParser};
 use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
 
@@ -58,6 +58,7 @@ macro_rules! attribute_parsers {
             use super::*;
             type Combine<T> = super::Combine<T, Early>;
             type Single<T> = super::Single<T, Early>;
+            type WithoutArgs<T> = super::WithoutArgs<T, Early>;
 
             attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
         }
@@ -65,6 +66,7 @@ macro_rules! attribute_parsers {
             use super::*;
             type Combine<T> = super::Combine<T, Late>;
             type Single<T> = super::Single<T, Late>;
+            type WithoutArgs<T> = super::WithoutArgs<T, Late>;
 
             attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
         }
@@ -116,31 +118,32 @@ attribute_parsers!(
         Combine<AllowConstFnUnstableParser>,
         Combine<AllowInternalUnstableParser>,
         Combine<ReprParser>,
+        Combine<TargetFeatureParser>,
         // tidy-alphabetical-end
 
         // tidy-alphabetical-start
-        Single<AsPtrParser>,
-        Single<ColdParser>,
-        Single<ConstContinueParser>,
-        Single<ConstStabilityIndirectParser>,
         Single<DeprecationParser>,
         Single<ExportNameParser>,
         Single<InlineParser>,
         Single<LinkNameParser>,
         Single<LinkSectionParser>,
-        Single<LoopMatchParser>,
-        Single<MayDangleParser>,
         Single<MustUseParser>,
-        Single<NoMangleParser>,
         Single<OptimizeParser>,
-        Single<PubTransparentParser>,
         Single<RustcForceInlineParser>,
         Single<RustcLayoutScalarValidRangeEnd>,
         Single<RustcLayoutScalarValidRangeStart>,
         Single<RustcObjectLifetimeDefaultParser>,
         Single<SkipDuringMethodDispatchParser>,
-        Single<TrackCallerParser>,
         Single<TransparencyParser>,
+        Single<WithoutArgs<AsPtrParser>>,
+        Single<WithoutArgs<ColdParser>>,
+        Single<WithoutArgs<ConstContinueParser>>,
+        Single<WithoutArgs<ConstStabilityIndirectParser>>,
+        Single<WithoutArgs<LoopMatchParser>>,
+        Single<WithoutArgs<MayDangleParser>>,
+        Single<WithoutArgs<NoMangleParser>>,
+        Single<WithoutArgs<PubTransparentParser>>,
+        Single<WithoutArgs<TrackCallerParser>>,
         // tidy-alphabetical-end
     ];
 );
@@ -187,7 +190,7 @@ impl Stage for Late {
     }
 }
 
-/// used when parsing attributes for miscelaneous things *before* ast lowering
+/// used when parsing attributes for miscellaneous things *before* ast lowering
 pub struct Early;
 /// used when parsing attributes during ast lowering
 pub struct Late;
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index df1b1eb60e1..c7844778332 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -562,7 +562,7 @@ mod llvm_enzyme {
     /// so instead we manually build something that should pass the type checker.
     /// We also add a inline_asm line, as one more barrier for rustc to prevent inlining
     /// or const propagation. inline_asm will also triggers an Enzyme crash if due to another
-    /// bug would ever try to accidentially differentiate this placeholder function body.
+    /// bug would ever try to accidentally differentiate this placeholder function body.
     /// Finally, we also add back_box usages of all input arguments, to prevent rustc
     /// from optimizing any arguments away.
     fn gen_enzyme_body(
@@ -606,7 +606,7 @@ mod llvm_enzyme {
             return body;
         }
 
-        // Everything from here onwards just tries to fullfil the return type. Fun!
+        // Everything from here onwards just tries to fulfil the return type. Fun!
 
         // having an active-only return means we'll drop the original return type.
         // So that can be treated identical to not having one in the first place.
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 9930eae3fe7..776658b9cca 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -107,7 +107,7 @@ fn call_simple_intrinsic<'ll, 'tcx>(
         sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]),
         sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]),
         // There are issues on x86_64 and aarch64 with the f128 variant,
-        // let's instead use the instrinsic fallback body.
+        // let's instead use the intrinsic fallback body.
         // sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]),
         sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]),
         sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]),
@@ -118,7 +118,7 @@ fn call_simple_intrinsic<'ll, 'tcx>(
         sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]),
         sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]),
         // There are issues on x86_64 and aarch64 with the f128 variant,
-        // let's instead use the instrinsic fallback body.
+        // let's instead use the intrinsic fallback body.
         // sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]),
         sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]),
         sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]),
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index b94716b89d6..7b00b2da6ba 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -40,7 +40,7 @@ unsafe extern "C" {
     pub(crate) fn LLVMDumpValue(V: &Value);
     pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
     pub(crate) fn LLVMGetReturnType(T: &Type) -> &Type;
-    pub(crate) fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);
+    pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value);
     pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 236568590be..4fe4c9bcbf2 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -861,7 +861,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>(
 
     // On big-endian, for values smaller than the slot size we'd have to align the read to the end
     // of the slot rather than the start. While the ISA and GCC support big-endian, all the Xtensa
-    // targets supported by rustc are litte-endian so don't worry about it.
+    // targets supported by rustc are little-endian so don't worry about it.
 
     // if from_regsave {
     //     unsafe { *regsave_value_ptr }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 84d63819343..63e9005da45 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -62,6 +62,10 @@ codegen_ssa_failed_to_get_layout = failed to get layout for {$ty}: {$err}
 
 codegen_ssa_failed_to_write = failed to write {$path}: {$error}
 
+codegen_ssa_feature_not_valid = the feature named `{$feature}` is not valid for this target
+    .label = `{$feature}` is not valid for this target
+    .help = consider removing the leading `+` in the feature name
+
 codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
 
 codegen_ssa_forbidden_ctarget_feature =
@@ -289,7 +293,7 @@ codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executab
 
 codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
 
-codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
+codegen_ssa_thorin_mixed_input_encodings = input objects have mixed encodings
 
 codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 4a2425967e4..343cb0eeca9 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2767,7 +2767,7 @@ fn add_upstream_rust_crates(
 
     if sess.target.is_like_aix {
         // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override
-        // the dependency name when outputing a shared library. Thus, `ld` will
+        // the dependency name when outputting a shared library. Thus, `ld` will
         // use the full path to shared libraries as the dependency if passed it
         // by default unless `noipath` is passed.
         // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command.
@@ -3051,7 +3051,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
     // Supported architecture names can be found in the source:
     // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648
     //
-    // Intentially verbose to ensure that the list always matches correctly
+    // Intentionally verbose to ensure that the list always matches correctly
     // with the list in the source above.
     let ld64_arch = match llvm_arch {
         "armv7k" => "armv7k",
@@ -3118,7 +3118,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
         // We do not currently know the actual SDK version though, so we have a few options:
         // 1. Use the minimum version supported by rustc.
         // 2. Use the same as the deployment target.
-        // 3. Use an arbitary recent version.
+        // 3. Use an arbitrary recent version.
         // 4. Omit the version.
         //
         // The first option is too low / too conservative, and means that users will not get the
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index d091c46d9c1..bf38c02e908 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -301,7 +301,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
                 "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2,
                 "n64" if !is_32bit => {}
                 "" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
-                "" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"),
+                "" => sess.dcx().fatal("LLVM ABI must be specified for 64-bit MIPS targets"),
                 s if is_32bit => {
                     sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s))
                 }
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 6e2143858de..2713ec07f97 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -141,6 +141,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         });
                     }
                 }
+                AttributeKind::TargetFeature(features, attr_span) => {
+                    let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
+                        tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
+                        continue;
+                    };
+                    let safe_target_features =
+                        matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
+                    codegen_fn_attrs.safe_target_features = safe_target_features;
+                    if safe_target_features {
+                        if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
+                            // The `#[target_feature]` attribute is allowed on
+                            // WebAssembly targets on all functions. Prior to stabilizing
+                            // the `target_feature_11` feature, `#[target_feature]` was
+                            // only permitted on unsafe functions because on most targets
+                            // execution of instructions that are not supported is
+                            // considered undefined behavior. For WebAssembly which is a
+                            // 100% safe target at execution time it's not possible to
+                            // execute undefined instructions, and even if a future
+                            // feature was added in some form for this it would be a
+                            // deterministic trap. There is no undefined behavior when
+                            // executing WebAssembly so `#[target_feature]` is allowed
+                            // on safe functions (but again, only for WebAssembly)
+                            //
+                            // Note that this is also allowed if `actually_rustdoc` so
+                            // if a target is documenting some wasm-specific code then
+                            // it's not spuriously denied.
+                            //
+                            // Now that `#[target_feature]` is permitted on safe functions,
+                            // this exception must still exist for allowing the attribute on
+                            // `main`, `start`, and other functions that are not usually
+                            // allowed.
+                        } else {
+                            check_target_feature_trait_unsafe(tcx, did, *attr_span);
+                        }
+                    }
+                    from_target_feature_attr(
+                        tcx,
+                        did,
+                        features,
+                        rust_target_features,
+                        &mut codegen_fn_attrs.target_features,
+                    );
+                }
                 AttributeKind::TrackCaller(attr_span) => {
                     let is_closure = tcx.is_closure_like(did.to_def_id());
 
@@ -190,49 +233,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
             }
             sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
-            sym::target_feature => {
-                let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
-                    tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn");
-                    continue;
-                };
-                let safe_target_features =
-                    matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
-                codegen_fn_attrs.safe_target_features = safe_target_features;
-                if safe_target_features {
-                    if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
-                        // The `#[target_feature]` attribute is allowed on
-                        // WebAssembly targets on all functions. Prior to stabilizing
-                        // the `target_feature_11` feature, `#[target_feature]` was
-                        // only permitted on unsafe functions because on most targets
-                        // execution of instructions that are not supported is
-                        // considered undefined behavior. For WebAssembly which is a
-                        // 100% safe target at execution time it's not possible to
-                        // execute undefined instructions, and even if a future
-                        // feature was added in some form for this it would be a
-                        // deterministic trap. There is no undefined behavior when
-                        // executing WebAssembly so `#[target_feature]` is allowed
-                        // on safe functions (but again, only for WebAssembly)
-                        //
-                        // Note that this is also allowed if `actually_rustdoc` so
-                        // if a target is documenting some wasm-specific code then
-                        // it's not spuriously denied.
-                        //
-                        // Now that `#[target_feature]` is permitted on safe functions,
-                        // this exception must still exist for allowing the attribute on
-                        // `main`, `start`, and other functions that are not usually
-                        // allowed.
-                    } else {
-                        check_target_feature_trait_unsafe(tcx, did, attr.span());
-                    }
-                }
-                from_target_feature_attr(
-                    tcx,
-                    did,
-                    attr,
-                    rust_target_features,
-                    &mut codegen_fn_attrs.target_features,
-                );
-            }
             sym::linkage => {
                 if let Some(val) = attr.value_str() {
                     let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
@@ -536,10 +536,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             .map(|features| (features.name.as_str(), true))
             .collect(),
     ) {
-        let span = tcx
-            .get_attrs(did, sym::target_feature)
-            .next()
-            .map_or_else(|| tcx.def_span(did), |a| a.span());
+        let span =
+            find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span)
+                .unwrap_or_else(|| tcx.def_span(did));
+
         tcx.dcx()
             .create_err(errors::TargetFeatureDisableOrEnable {
                 features,
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 1950a35b364..086c069745c 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1292,3 +1292,14 @@ pub(crate) struct NoMangleNameless {
     pub span: Span,
     pub definition: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_feature_not_valid)]
+pub(crate) struct FeatureNotValid<'a> {
+    pub feature: &'a str,
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[help]
+    pub plus_hint: bool,
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 7ef04213d32..60cf4e28b5a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -1117,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     // While optimizations will remove no-op transmutes, they might still be
     // there in debug or things that aren't no-op in MIR because they change
     // the Rust type but not the underlying layout/niche.
-    if from_scalar == to_scalar {
+    if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
         return imm;
     }
 
@@ -1136,13 +1136,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
 
     imm = match (from_scalar.primitive(), to_scalar.primitive()) {
-        (Int(..) | Float(_), Int(..) | Float(_)) => {
-            if from_backend_ty == to_backend_ty {
-                imm
-            } else {
-                bx.bitcast(imm, to_backend_ty)
-            }
-        }
+        (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
         (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
         (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
         (Pointer(..), Int(..)) => {
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 67ac619091b..53df99993f0 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,8 +1,6 @@
 use rustc_attr_data_structures::InstructionSetAttr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
-use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
@@ -12,110 +10,85 @@ use rustc_session::Session;
 use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
-use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability};
+use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
 use smallvec::SmallVec;
 
-use crate::errors;
+use crate::errors::FeatureNotValid;
+use crate::{errors, target_features};
 
 /// Compute the enabled target features from the `#[target_feature]` function attribute.
 /// Enabled target features are added to `target_features`.
 pub(crate) fn from_target_feature_attr(
     tcx: TyCtxt<'_>,
     did: LocalDefId,
-    attr: &hir::Attribute,
+    features: &[(Symbol, Span)],
     rust_target_features: &UnordMap<String, target_features::Stability>,
     target_features: &mut Vec<TargetFeature>,
 ) {
-    let Some(list) = attr.meta_item_list() else { return };
-    let bad_item = |span| {
-        let msg = "malformed `target_feature` attribute input";
-        let code = "enable = \"..\"";
-        tcx.dcx()
-            .struct_span_err(span, msg)
-            .with_span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
-            .emit();
-    };
     let rust_features = tcx.features();
     let abi_feature_constraints = tcx.sess.target.abi_required_features();
-    for item in list {
-        // Only `enable = ...` is accepted in the meta-item list.
-        if !item.has_name(sym::enable) {
-            bad_item(item.span());
-            continue;
-        }
-
-        // Must be of the form `enable = "..."` (a string).
-        let Some(value) = item.value_str() else {
-            bad_item(item.span());
+    for &(feature, feature_span) in features {
+        let feature_str = feature.as_str();
+        let Some(stability) = rust_target_features.get(feature_str) else {
+            let plus_hint = feature_str
+                .strip_prefix('+')
+                .is_some_and(|stripped| rust_target_features.contains_key(stripped));
+            tcx.dcx().emit_err(FeatureNotValid {
+                feature: feature_str,
+                span: feature_span,
+                plus_hint,
+            });
             continue;
         };
 
-        // We allow comma separation to enable multiple features.
-        for feature in value.as_str().split(',') {
-            let Some(stability) = rust_target_features.get(feature) else {
-                let msg = format!("the feature named `{feature}` is not valid for this target");
-                let mut err = tcx.dcx().struct_span_err(item.span(), msg);
-                err.span_label(item.span(), format!("`{feature}` is not valid for this target"));
-                if let Some(stripped) = feature.strip_prefix('+') {
-                    let valid = rust_target_features.contains_key(stripped);
-                    if valid {
-                        err.help("consider removing the leading `+` in the feature name");
-                    }
-                }
-                err.emit();
-                continue;
-            };
-
-            // Only allow target features whose feature gates have been enabled
-            // and which are permitted to be toggled.
-            if let Err(reason) = stability.toggle_allowed() {
-                tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
-                    span: item.span(),
-                    feature,
-                    reason,
-                });
-            } else if let Some(nightly_feature) = stability.requires_nightly()
-                && !rust_features.enabled(nightly_feature)
-            {
-                feature_err(
-                    &tcx.sess,
-                    nightly_feature,
-                    item.span(),
-                    format!("the target feature `{feature}` is currently unstable"),
-                )
-                .emit();
-            } else {
-                // Add this and the implied features.
-                let feature_sym = Symbol::intern(feature);
-                for &name in tcx.implied_target_features(feature_sym) {
-                    // But ensure the ABI does not forbid enabling this.
-                    // Here we do assume that the backend doesn't add even more implied features
-                    // we don't know about, at least no features that would have ABI effects!
-                    // We skip this logic in rustdoc, where we want to allow all target features of
-                    // all targets, so we can't check their ABI compatibility and anyway we are not
-                    // generating code so "it's fine".
-                    if !tcx.sess.opts.actually_rustdoc {
-                        if abi_feature_constraints.incompatible.contains(&name.as_str()) {
-                            // For "neon" specifically, we emit an FCW instead of a hard error.
-                            // See <https://github.com/rust-lang/rust/issues/134375>.
-                            if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" {
-                                tcx.emit_node_span_lint(
-                                    AARCH64_SOFTFLOAT_NEON,
-                                    tcx.local_def_id_to_hir_id(did),
-                                    item.span(),
-                                    errors::Aarch64SoftfloatNeon,
-                                );
-                            } else {
-                                tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
-                                    span: item.span(),
-                                    feature: name.as_str(),
-                                    reason: "this feature is incompatible with the target ABI",
-                                });
-                            }
+        // Only allow target features whose feature gates have been enabled
+        // and which are permitted to be toggled.
+        if let Err(reason) = stability.toggle_allowed() {
+            tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
+                span: feature_span,
+                feature: feature_str,
+                reason,
+            });
+        } else if let Some(nightly_feature) = stability.requires_nightly()
+            && !rust_features.enabled(nightly_feature)
+        {
+            feature_err(
+                &tcx.sess,
+                nightly_feature,
+                feature_span,
+                format!("the target feature `{feature}` is currently unstable"),
+            )
+            .emit();
+        } else {
+            // Add this and the implied features.
+            for &name in tcx.implied_target_features(feature) {
+                // But ensure the ABI does not forbid enabling this.
+                // Here we do assume that the backend doesn't add even more implied features
+                // we don't know about, at least no features that would have ABI effects!
+                // We skip this logic in rustdoc, where we want to allow all target features of
+                // all targets, so we can't check their ABI compatibility and anyway we are not
+                // generating code so "it's fine".
+                if !tcx.sess.opts.actually_rustdoc {
+                    if abi_feature_constraints.incompatible.contains(&name.as_str()) {
+                        // For "neon" specifically, we emit an FCW instead of a hard error.
+                        // See <https://github.com/rust-lang/rust/issues/134375>.
+                        if tcx.sess.target.arch == "aarch64" && name.as_str() == "neon" {
+                            tcx.emit_node_span_lint(
+                                AARCH64_SOFTFLOAT_NEON,
+                                tcx.local_def_id_to_hir_id(did),
+                                feature_span,
+                                errors::Aarch64SoftfloatNeon,
+                            );
+                        } else {
+                            tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
+                                span: feature_span,
+                                feature: name.as_str(),
+                                reason: "this feature is incompatible with the target ABI",
+                            });
                         }
                     }
-                    target_features.push(TargetFeature { name, implied: name != feature_sym })
                 }
+                target_features.push(TargetFeature { name, implied: name != feature })
             }
         }
     }
@@ -457,7 +430,7 @@ pub(crate) fn provide(providers: &mut Providers) {
                                     // one, just keep it.
                                 }
                                 _ => {
-                                    // Overwrite stabilite.
+                                    // Overwrite stability.
                                     occupied_entry.insert(stability);
                                 }
                             }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index d19de6f5d26..9d367748c2a 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -87,7 +87,7 @@ pub trait BuilderMethods<'a, 'tcx>:
     //
     // This function is opt-in for back ends.
     //
-    // The default implementation calls `self.expect()` before emiting the branch
+    // The default implementation calls `self.expect()` before emitting the branch
     // by calling `self.cond_br()`
     fn cond_br_with_expect(
         &mut self,
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index d8421415225..9ab8e0692e1 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -82,7 +82,7 @@ pub fn rustc_allow_const_fn_unstable(
 ) -> bool {
     let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
 
-    attrs::find_attr!(attrs, attrs::AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate))
+    attrs::find_attr!(attrs, attrs::AttributeKind::AllowConstFnUnstable(syms, _) if syms.contains(&feature_gate))
 }
 
 /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 317b1229a90..76fa744361a 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -10,7 +10,7 @@ use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
 use rustc_middle::mir::AssertMessage;
 use rustc_middle::mir::interpret::ReportedErrorInfo;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
+use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::{Span, Symbol, sym};
@@ -23,8 +23,8 @@ use crate::fluent_generated as fluent;
 use crate::interpret::{
     self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
     GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar,
-    compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom,
-    throw_unsup, throw_unsup_format,
+    compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub,
+    throw_ub_custom, throw_unsup, throw_unsup_format,
 };
 
 /// When hitting this many interpreted terminators we emit a deny by default lint
@@ -462,6 +462,44 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
             // (We know the value here in the machine of course, but this is the runtime of that code,
             // not the optimization stage.)
             sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?,
+
+            // We handle these here since Miri does not want to have them.
+            sym::assert_inhabited
+            | sym::assert_zero_valid
+            | sym::assert_mem_uninitialized_valid => {
+                let ty = instance.args.type_at(0);
+                let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap();
+
+                let should_panic = !ecx
+                    .tcx
+                    .check_validity_requirement((requirement, ecx.typing_env().as_query_input(ty)))
+                    .map_err(|_| err_inval!(TooGeneric))?;
+
+                if should_panic {
+                    let layout = ecx.layout_of(ty)?;
+
+                    let msg = match requirement {
+                        // For *all* intrinsics we first check `is_uninhabited` to give a more specific
+                        // error message.
+                        _ if layout.is_uninhabited() => format!(
+                            "aborted execution: attempted to instantiate uninhabited type `{ty}`"
+                        ),
+                        ValidityRequirement::Inhabited => bug!("handled earlier"),
+                        ValidityRequirement::Zero => format!(
+                            "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid"
+                        ),
+                        ValidityRequirement::UninitMitigated0x01Fill => format!(
+                            "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid"
+                        ),
+                        ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"),
+                    };
+
+                    Self::panic_nounwind(ecx, &msg)?;
+                    // Skip the `return_to_block` at the end (we panicked, we do not return).
+                    return interp_ok(None);
+                }
+            }
+
             _ => {
                 // We haven't handled the intrinsic, let's see if we can use a fallback body.
                 if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index d7cede71293..378ed6d0e10 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -7,7 +7,7 @@ use std::assert_matches::assert_matches;
 use rustc_abi::Size;
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
-use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement};
+use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{bug, ty};
 use rustc_span::{Symbol, sym};
@@ -17,8 +17,8 @@ use super::memory::MemoryKind;
 use super::util::ensure_monomorphic_enough;
 use super::{
     Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy,
-    PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom,
-    err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
+    PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format,
+    interp_ok, throw_inval, throw_ub_custom, throw_ub_format,
 };
 use crate::fluent_generated as fluent;
 
@@ -372,41 +372,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.exact_div(&val, &size, dest)?;
             }
 
-            sym::assert_inhabited
-            | sym::assert_zero_valid
-            | sym::assert_mem_uninitialized_valid => {
-                let ty = instance.args.type_at(0);
-                let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap();
-
-                let should_panic = !self
-                    .tcx
-                    .check_validity_requirement((requirement, self.typing_env.as_query_input(ty)))
-                    .map_err(|_| err_inval!(TooGeneric))?;
-
-                if should_panic {
-                    let layout = self.layout_of(ty)?;
-
-                    let msg = match requirement {
-                        // For *all* intrinsics we first check `is_uninhabited` to give a more specific
-                        // error message.
-                        _ if layout.is_uninhabited() => format!(
-                            "aborted execution: attempted to instantiate uninhabited type `{ty}`"
-                        ),
-                        ValidityRequirement::Inhabited => bug!("handled earlier"),
-                        ValidityRequirement::Zero => format!(
-                            "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid"
-                        ),
-                        ValidityRequirement::UninitMitigated0x01Fill => format!(
-                            "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid"
-                        ),
-                        ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"),
-                    };
-
-                    M::panic_nounwind(self, &msg)?;
-                    // Skip the `return_to_block` at the end (we panicked, we do not return).
-                    return interp_ok(true);
-                }
-            }
             sym::simd_insert => {
                 let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
                 let elem = &args[2];
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 3b36bb85985..ff822b52a8d 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -655,7 +655,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// The caller is responsible for calling the access hooks!
     ///
     /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
-    fn get_alloc_raw(
+    pub fn get_alloc_raw(
         &self,
         id: AllocId,
     ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>> {
@@ -757,7 +757,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ///
     /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the
     /// allocation.
-    fn get_alloc_raw_mut(
+    ///
+    /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
+    pub fn get_alloc_raw_mut(
         &mut self,
         id: AllocId,
     ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)> {
@@ -976,15 +978,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         interp_ok(())
     }
 
-    /// Handle the effect an FFI call might have on the state of allocations.
-    /// This overapproximates the modifications which external code might make to memory:
-    /// We set all reachable allocations as initialized, mark all reachable provenances as exposed
-    /// and overwrite them with `Provenance::WILDCARD`.
-    ///
-    /// The allocations in `ids` are assumed to be already exposed.
-    pub fn prepare_for_native_call(&mut self, ids: Vec<AllocId>) -> InterpResult<'tcx> {
+    /// Visit all allocations reachable from the given start set, by recursively traversing the
+    /// provenance information of those allocations.
+    pub fn visit_reachable_allocs(
+        &mut self,
+        start: Vec<AllocId>,
+        mut visit: impl FnMut(&mut Self, AllocId, &AllocInfo) -> InterpResult<'tcx>,
+    ) -> InterpResult<'tcx> {
         let mut done = FxHashSet::default();
-        let mut todo = ids;
+        let mut todo = start;
         while let Some(id) = todo.pop() {
             if !done.insert(id) {
                 // We already saw this allocation before, don't process it again.
@@ -992,31 +994,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             }
             let info = self.get_alloc_info(id);
 
-            // If there is no data behind this pointer, skip this.
-            if !matches!(info.kind, AllocKind::LiveData) {
-                continue;
-            }
-
-            // Expose all provenances in this allocation, and add them to `todo`.
-            let alloc = self.get_alloc_raw(id)?;
-            for prov in alloc.provenance().provenances() {
-                M::expose_provenance(self, prov)?;
-                if let Some(id) = prov.get_alloc_id() {
-                    todo.push(id);
+            // Recurse, if there is data here.
+            // Do this *before* invoking the callback, as the callback might mutate the
+            // allocation and e.g. replace all provenance by wildcards!
+            if matches!(info.kind, AllocKind::LiveData) {
+                let alloc = self.get_alloc_raw(id)?;
+                for prov in alloc.provenance().provenances() {
+                    if let Some(id) = prov.get_alloc_id() {
+                        todo.push(id);
+                    }
                 }
             }
-            // Also expose the provenance of the interpreter-level allocation, so it can
-            // be read by FFI. The `black_box` is defensive programming as LLVM likes
-            // to (incorrectly) optimize away ptr2int casts whose result is unused.
-            std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance());
-
-            // Prepare for possible write from native code if mutable.
-            if info.mutbl.is_mut() {
-                self.get_alloc_raw_mut(id)?
-                    .0
-                    .prepare_for_native_write()
-                    .map_err(|e| e.to_interp_error(id))?;
-            }
+
+            // Call the callback.
+            visit(self, id, &info)?;
         }
         interp_ok(())
     }
@@ -1073,7 +1064,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             todo.extend(static_roots(self));
             while let Some(id) = todo.pop() {
                 if reachable.insert(id) {
-                    // This is a new allocation, add the allocation it points to `todo`.
+                    // This is a new allocation, add the allocations it points to `todo`.
+                    // We only need to care about `alloc_map` memory here, as entirely unchanged
+                    // global memory cannot point to memory relevant for the leak check.
                     if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
                         todo.extend(
                             alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()),
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index a3cd35ff0bb..e2284729efd 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -572,7 +572,7 @@ where
             Right((local, offset, locals_addr, layout)) => {
                 if offset.is_some() {
                     // This has been projected to a part of this local, or had the type changed.
-                    // FIMXE: there are cases where we could still avoid allocating an mplace.
+                    // FIXME: there are cases where we could still avoid allocating an mplace.
                     Left(place.force_mplace(self)?)
                 } else {
                     debug_assert_eq!(locals_addr, self.frame().locals_addr());
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index e26cf0a4900..fc4d13af8c4 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -865,7 +865,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     fn add_data_range(&mut self, ptr: Pointer<Option<M::Provenance>>, size: Size) {
         if let Some(data_bytes) = self.data_bytes.as_mut() {
             // We only have to store the offset, the rest is the same for all pointers here.
-            // The logic is agnostic to wether the offset is relative or absolute as long as
+            // The logic is agnostic to whether the offset is relative or absolute as long as
             // it is consistent.
             let (_prov, offset) = ptr.into_raw_parts();
             // Add this.
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index d7e97f32bae..4ca39bbc68e 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -69,7 +69,7 @@ fn check_validity_requirement_strict<'tcx>(
     // require dereferenceability also require non-null, we don't actually get any false negatives
     // due to this.
     // The value we are validating is temporary and discarded at the end of this function, so
-    // there is no point in reseting provenance and padding.
+    // there is no point in resetting provenance and padding.
     cx.validate_operand(
         &allocated.into(),
         /*recursive*/ false,
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 36649a36070..1b4db7adc27 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -88,6 +88,7 @@ use std::fmt::Display;
 use std::intrinsics::unlikely;
 use std::path::Path;
 use std::sync::Arc;
+use std::sync::atomic::Ordering;
 use std::time::{Duration, Instant};
 use std::{fs, process};
 
@@ -99,12 +100,15 @@ use tracing::warn;
 
 use crate::fx::FxHashMap;
 use crate::outline;
+use crate::sync::AtomicU64;
 
 bitflags::bitflags! {
     #[derive(Clone, Copy)]
     struct EventFilter: u16 {
         const GENERIC_ACTIVITIES  = 1 << 0;
         const QUERY_PROVIDERS     = 1 << 1;
+        /// Store detailed instant events, including timestamp and thread ID,
+        /// per each query cache hit. Note that this is quite expensive.
         const QUERY_CACHE_HITS    = 1 << 2;
         const QUERY_BLOCKED       = 1 << 3;
         const INCR_CACHE_LOADS    = 1 << 4;
@@ -113,16 +117,20 @@ bitflags::bitflags! {
         const FUNCTION_ARGS       = 1 << 6;
         const LLVM                = 1 << 7;
         const INCR_RESULT_HASHING = 1 << 8;
-        const ARTIFACT_SIZES = 1 << 9;
+        const ARTIFACT_SIZES      = 1 << 9;
+        /// Store aggregated counts of cache hits per query invocation.
+        const QUERY_CACHE_HIT_COUNTS  = 1 << 10;
 
         const DEFAULT = Self::GENERIC_ACTIVITIES.bits() |
                         Self::QUERY_PROVIDERS.bits() |
                         Self::QUERY_BLOCKED.bits() |
                         Self::INCR_CACHE_LOADS.bits() |
                         Self::INCR_RESULT_HASHING.bits() |
-                        Self::ARTIFACT_SIZES.bits();
+                        Self::ARTIFACT_SIZES.bits() |
+                        Self::QUERY_CACHE_HIT_COUNTS.bits();
 
         const ARGS = Self::QUERY_KEYS.bits() | Self::FUNCTION_ARGS.bits();
+        const QUERY_CACHE_HIT_COMBINED = Self::QUERY_CACHE_HITS.bits() | Self::QUERY_CACHE_HIT_COUNTS.bits();
     }
 }
 
@@ -134,6 +142,7 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
     ("generic-activity", EventFilter::GENERIC_ACTIVITIES),
     ("query-provider", EventFilter::QUERY_PROVIDERS),
     ("query-cache-hit", EventFilter::QUERY_CACHE_HITS),
+    ("query-cache-hit-count", EventFilter::QUERY_CACHE_HITS),
     ("query-blocked", EventFilter::QUERY_BLOCKED),
     ("incr-cache-load", EventFilter::INCR_CACHE_LOADS),
     ("query-keys", EventFilter::QUERY_KEYS),
@@ -411,13 +420,24 @@ impl SelfProfilerRef {
         #[inline(never)]
         #[cold]
         fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) {
-            profiler_ref.instant_query_event(
-                |profiler| profiler.query_cache_hit_event_kind,
-                query_invocation_id,
-            );
+            if profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) {
+                profiler_ref
+                    .profiler
+                    .as_ref()
+                    .unwrap()
+                    .increment_query_cache_hit_counters(QueryInvocationId(query_invocation_id.0));
+            }
+            if unlikely(profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) {
+                profiler_ref.instant_query_event(
+                    |profiler| profiler.query_cache_hit_event_kind,
+                    query_invocation_id,
+                );
+            }
         }
 
-        if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) {
+        // We check both kinds of query cache hit events at once, to reduce overhead in the
+        // common case (with self-profile disabled).
+        if unlikely(self.event_filter_mask.intersects(EventFilter::QUERY_CACHE_HIT_COMBINED)) {
             cold_call(self, query_invocation_id);
         }
     }
@@ -489,6 +509,35 @@ impl SelfProfilerRef {
         self.profiler.as_ref().map(|p| p.get_or_alloc_cached_string(s))
     }
 
+    /// Store query cache hits to the self-profile log.
+    /// Should be called once at the end of the compilation session.
+    ///
+    /// The cache hits are stored per **query invocation**, not **per query kind/type**.
+    /// `analyzeme` can later deduplicate individual query labels from the QueryInvocationId event
+    /// IDs.
+    pub fn store_query_cache_hits(&self) {
+        if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) {
+            let profiler = self.profiler.as_ref().unwrap();
+            let query_hits = profiler.query_hits.read();
+            let builder = EventIdBuilder::new(&profiler.profiler);
+            let thread_id = get_thread_id();
+            for (query_invocation, hit_count) in query_hits.iter().enumerate() {
+                let hit_count = hit_count.load(Ordering::Relaxed);
+                // No need to record empty cache hit counts
+                if hit_count > 0 {
+                    let event_id =
+                        builder.from_label(StringId::new_virtual(query_invocation as u64));
+                    profiler.profiler.record_integer_event(
+                        profiler.query_cache_hit_count_event_kind,
+                        event_id,
+                        thread_id,
+                        hit_count,
+                    );
+                }
+            }
+        }
+    }
+
     #[inline]
     pub fn enabled(&self) -> bool {
         self.profiler.is_some()
@@ -537,6 +586,19 @@ pub struct SelfProfiler {
 
     string_cache: RwLock<FxHashMap<String, StringId>>,
 
+    /// Recording individual query cache hits as "instant" measureme events
+    /// is incredibly expensive. Instead of doing that, we simply aggregate
+    /// cache hit *counts* per query invocation, and then store the final count
+    /// of cache hits per invocation at the end of the compilation session.
+    ///
+    /// With this approach, we don't know the individual thread IDs and timestamps
+    /// of cache hits, but it has very little overhead on top of `-Zself-profile`.
+    /// Recording the cache hits as individual events made compilation 3-5x slower.
+    ///
+    /// Query invocation IDs should be monotonic integers, so we can store them in a vec,
+    /// rather than using a hashmap.
+    query_hits: RwLock<Vec<AtomicU64>>,
+
     query_event_kind: StringId,
     generic_activity_event_kind: StringId,
     incremental_load_result_event_kind: StringId,
@@ -544,6 +606,8 @@ pub struct SelfProfiler {
     query_blocked_event_kind: StringId,
     query_cache_hit_event_kind: StringId,
     artifact_size_event_kind: StringId,
+    /// Total cache hits per query invocation
+    query_cache_hit_count_event_kind: StringId,
 }
 
 impl SelfProfiler {
@@ -573,6 +637,7 @@ impl SelfProfiler {
         let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
         let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
         let artifact_size_event_kind = profiler.alloc_string("ArtifactSize");
+        let query_cache_hit_count_event_kind = profiler.alloc_string("QueryCacheHitCount");
 
         let mut event_filter_mask = EventFilter::empty();
 
@@ -618,6 +683,8 @@ impl SelfProfiler {
             query_blocked_event_kind,
             query_cache_hit_event_kind,
             artifact_size_event_kind,
+            query_cache_hit_count_event_kind,
+            query_hits: Default::default(),
         })
     }
 
@@ -627,6 +694,25 @@ impl SelfProfiler {
         self.profiler.alloc_string(s)
     }
 
+    /// Store a cache hit of a query invocation
+    pub fn increment_query_cache_hit_counters(&self, id: QueryInvocationId) {
+        // Fast path: assume that the query was already encountered before, and just record
+        // a cache hit.
+        let mut guard = self.query_hits.upgradable_read();
+        let query_hits = &guard;
+        let index = id.0 as usize;
+        if index < query_hits.len() {
+            // We only want to increment the count, no other synchronization is required
+            query_hits[index].fetch_add(1, Ordering::Relaxed);
+        } else {
+            // If not, we need to extend the query hit map to the highest observed ID
+            guard.with_upgraded(|vec| {
+                vec.resize_with(index + 1, || AtomicU64::new(0));
+                vec[index] = AtomicU64::from(1);
+            });
+        }
+    }
+
     /// Gets a `StringId` for the given string. This method makes sure that
     /// any strings going through it will only be allocated once in the
     /// profiling data.
diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs
index 3b448c056b7..0ffa6b3205f 100644
--- a/compiler/rustc_data_structures/src/vec_cache.rs
+++ b/compiler/rustc_data_structures/src/vec_cache.rs
@@ -257,7 +257,7 @@ unsafe impl<K: Idx, #[may_dangle] V, I> Drop for VecCache<K, V, I> {
         // we are also guaranteed to just need to deallocate any large arrays (not iterate over
         // contents).
         //
-        // Confirm no need to deallocate invidual entries. Note that `V: Copy` is asserted on
+        // Confirm no need to deallocate individual entries. Note that `V: Copy` is asserted on
         // insert/lookup but not necessarily construction, primarily to avoid annoyingly propagating
         // the bounds into struct definitions everywhere.
         assert!(!std::mem::needs_drop::<K>());
diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs
index f02387d8335..e1b1b32cd3e 100644
--- a/compiler/rustc_errors/src/markdown/parse.rs
+++ b/compiler/rustc_errors/src/markdown/parse.rs
@@ -352,7 +352,7 @@ fn normalize<'a>(MdStream(stream): MdStream<'a>, linkdefs: &mut Vec<MdTree<'a>>)
     let new_defs = stream.iter().filter(|tt| matches!(tt, MdTree::LinkDef { .. }));
     linkdefs.extend(new_defs.cloned());
 
-    // Run plaintest expansions on types that need it, call this function on nested types
+    // Run plaintext expansions on types that need it, call this function on nested types
     for item in stream {
         match item {
             MdTree::PlainText(txt) => expand_plaintext(txt, &mut new_stream, MdTree::PlainText),
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index fe76d9e0b64..80f6e9d9fc4 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -880,7 +880,7 @@ impl SyntaxExtension {
         is_local: bool,
     ) -> SyntaxExtension {
         let allow_internal_unstable =
-            find_attr!(attrs, AttributeKind::AllowInternalUnstable(i) => i)
+            find_attr!(attrs, AttributeKind::AllowInternalUnstable(i, _) => i)
                 .map(|i| i.as_slice())
                 .unwrap_or_default();
         // FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 14b8cc90d97..a333f2c7cb7 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -195,6 +195,7 @@ impl<'a> ExtCtxt<'a> {
             },
             trait_ref: self.trait_ref(path),
             span,
+            parens: ast::Parens::No,
         }
     }
 
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 99aa376626d..c607a3a3652 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -195,38 +195,6 @@ impl<'dcx> CollectTrackerAndEmitter<'dcx, '_> {
     }
 }
 
-/// Currently used by macro_rules! compilation to extract a little information from the `Failure`
-/// case.
-pub(crate) struct FailureForwarder<'matcher> {
-    expected_token: Option<&'matcher Token>,
-}
-
-impl<'matcher> FailureForwarder<'matcher> {
-    pub(crate) fn new() -> Self {
-        Self { expected_token: None }
-    }
-}
-
-impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> {
-    type Failure = (Token, u32, &'static str);
-
-    fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure {
-        (tok, position, msg)
-    }
-
-    fn description() -> &'static str {
-        "failure-forwarder"
-    }
-
-    fn set_expected_token(&mut self, tok: &'matcher Token) {
-        self.expected_token = Some(tok);
-    }
-
-    fn get_expected_token(&self) -> Option<&'matcher Token> {
-        self.expected_token
-    }
-}
-
 pub(super) fn emit_frag_parse_err(
     mut e: Diag<'_>,
     parser: &Parser<'_>,
@@ -321,7 +289,7 @@ enum ExplainDocComment {
     },
 }
 
-pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) {
+fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) {
     if let Ok(src) = sm.span_to_snippet(span) {
         if src.starts_with("///") || src.starts_with("/**") {
             err.subdiagnostic(ExplainDocComment::Outer { span });
@@ -333,7 +301,7 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa
 
 /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
 /// other tokens, this is "unexpected token...".
-pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> {
+fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> {
     if let Some(expected_token) = expected_token {
         Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok)))
     } else {
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index dc2d46c4a14..bbdff866feb 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -105,8 +105,6 @@
 //! stored when entering a macro definition starting from the state in which the meta-variable is
 //! bound.
 
-use std::iter;
-
 use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::{DUMMY_NODE_ID, NodeId};
 use rustc_data_structures::fx::FxHashMap;
@@ -190,29 +188,22 @@ struct MacroState<'a> {
     ops: SmallVec<[KleeneToken; 1]>,
 }
 
-/// Checks that meta-variables are used correctly in a macro definition.
+/// Checks that meta-variables are used correctly in one rule of a macro definition.
 ///
 /// Arguments:
 /// - `psess` is used to emit diagnostics and lints
 /// - `node_id` is used to emit lints
-/// - `span` is used when no spans are available
-/// - `lhses` and `rhses` should have the same length and represent the macro definition
+/// - `lhs` and `rhs` represent the rule
 pub(super) fn check_meta_variables(
     psess: &ParseSess,
     node_id: NodeId,
-    span: Span,
-    lhses: &[TokenTree],
-    rhses: &[TokenTree],
+    lhs: &TokenTree,
+    rhs: &TokenTree,
 ) -> Result<(), ErrorGuaranteed> {
-    if lhses.len() != rhses.len() {
-        psess.dcx().span_bug(span, "length mismatch between LHSes and RHSes")
-    }
     let mut guar = None;
-    for (lhs, rhs) in iter::zip(lhses, rhses) {
-        let mut binders = Binders::default();
-        check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar);
-        check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar);
-    }
+    let mut binders = Binders::default();
+    check_binders(psess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar);
+    check_occurrences(psess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar);
     guar.map_or(Ok(()), Err)
 }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 802e43209a5..3f1fc841ea3 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -536,8 +536,6 @@ impl TtParser {
                         // The separator matches the current token. Advance past it.
                         mp.idx += 1;
                         self.next_mps.push(mp);
-                    } else {
-                        track.set_expected_token(separator);
                     }
                 }
                 &MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 432ab324740..dad2fd99ef2 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -19,12 +19,13 @@ use rustc_lint_defs::BuiltinLintDiag;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
 };
-use rustc_parse::parser::{ParseNtResult, Parser, Recovery};
+use rustc_parse::exp;
+use rustc_parse::parser::{Parser, Recovery};
 use rustc_session::Session;
 use rustc_session::parse::ParseSess;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym};
+use rustc_span::{Ident, Span, kw, sym};
 use tracing::{debug, instrument, trace, trace_span};
 
 use super::macro_parser::{NamedMatches, NamedParseResult};
@@ -34,8 +35,6 @@ use crate::base::{
     SyntaxExtensionKind, TTMacroExpander,
 };
 use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
-use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
-use crate::mbe::macro_parser::NamedMatch::*;
 use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
 use crate::mbe::transcribe::transcribe;
 use crate::mbe::{self, KleeneOp, macro_check};
@@ -168,11 +167,6 @@ pub(super) trait Tracker<'matcher> {
     fn recovery() -> Recovery {
         Recovery::Forbidden
     }
-
-    fn set_expected_token(&mut self, _tok: &'matcher Token) {}
-    fn get_expected_token(&self) -> Option<&'matcher Token> {
-        None
-    }
 }
 
 /// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to
@@ -360,11 +354,6 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
     Err(CanRetry::Yes)
 }
 
-// Note that macro-by-example's input is also matched against a token tree:
-//                   $( $lhs:tt => $rhs:tt );+
-//
-// Holy self-referential!
-
 /// Converts a macro item into a syntax extension.
 pub fn compile_declarative_macro(
     sess: &Session,
@@ -390,157 +379,66 @@ pub fn compile_declarative_macro(
     };
     let dummy_syn_ext = |guar| (mk_syn_ext(Arc::new(DummyExpander(guar))), Vec::new());
 
-    let lhs_nm = Ident::new(sym::lhs, span);
-    let rhs_nm = Ident::new(sym::rhs, span);
-    let tt_spec = NonterminalKind::TT;
     let macro_rules = macro_def.macro_rules;
+    let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
 
-    // Parse the macro_rules! invocation
-
-    // The pattern that macro_rules matches.
-    // The grammar for macro_rules! is:
-    // $( $lhs:tt => $rhs:tt );+
-    // ...quasiquoting this would be nice.
-    // These spans won't matter, anyways
-    let argument_gram = vec![
-        mbe::TokenTree::Sequence(
-            DelimSpan::dummy(),
-            mbe::SequenceRepetition {
-                tts: vec![
-                    mbe::TokenTree::MetaVarDecl { span, name: lhs_nm, kind: tt_spec },
-                    mbe::TokenTree::token(token::FatArrow, span),
-                    mbe::TokenTree::MetaVarDecl { span, name: rhs_nm, kind: tt_spec },
-                ],
-                separator: Some(Token::new(
-                    if macro_rules { token::Semi } else { token::Comma },
-                    span,
-                )),
-                kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span),
-                num_captures: 2,
-            },
-        ),
-        // to phase into semicolon-termination instead of semicolon-separation
-        mbe::TokenTree::Sequence(
-            DelimSpan::dummy(),
-            mbe::SequenceRepetition {
-                tts: vec![mbe::TokenTree::token(
-                    if macro_rules { token::Semi } else { token::Comma },
-                    span,
-                )],
-                separator: None,
-                kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span),
-                num_captures: 0,
-            },
-        ),
-    ];
-    // Convert it into `MatcherLoc` form.
-    let argument_gram = mbe::macro_parser::compute_locs(&argument_gram);
-
-    let create_parser = || {
-        let body = macro_def.body.tokens.clone();
-        Parser::new(&sess.psess, body, rustc_parse::MACRO_ARGUMENTS)
-    };
-
-    let parser = create_parser();
-    let mut tt_parser =
-        TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
-    let argument_map =
-        match tt_parser.parse_tt(&mut Cow::Owned(parser), &argument_gram, &mut NoopTracker) {
-            Success(m) => m,
-            Failure(()) => {
-                debug!("failed to parse macro tt");
-                // The fast `NoopTracker` doesn't have any info on failure, so we need to retry it
-                // with another one that gives us the information we need.
-                // For this we need to reclone the macro body as the previous parser consumed it.
-                let retry_parser = create_parser();
-
-                let mut track = diagnostics::FailureForwarder::new();
-                let parse_result =
-                    tt_parser.parse_tt(&mut Cow::Owned(retry_parser), &argument_gram, &mut track);
-                let Failure((token, _, msg)) = parse_result else {
-                    unreachable!("matcher returned something other than Failure after retry");
-                };
-
-                let s = parse_failure_msg(&token, track.get_expected_token());
-                let sp = token.span.substitute_dummy(span);
-                let mut err = sess.dcx().struct_span_err(sp, s);
-                err.span_label(sp, msg);
-                annotate_doc_comment(&mut err, sess.source_map(), sp);
-                let guar = err.emit();
-                return dummy_syn_ext(guar);
-            }
-            Error(sp, msg) => {
-                let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg);
-                return dummy_syn_ext(guar);
-            }
-            ErrorReported(guar) => {
-                return dummy_syn_ext(guar);
-            }
-        };
+    let body = macro_def.body.tokens.clone();
+    let mut p = Parser::new(&sess.psess, body, rustc_parse::MACRO_ARGUMENTS);
 
+    // Don't abort iteration early, so that multiple errors can be reported.
     let mut guar = None;
     let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err());
 
-    // Extract the arguments:
-    let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] {
-        MatchedSeq(s) => s
-            .iter()
-            .map(|m| {
-                if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
-                    let tt = mbe::quoted::parse(
-                        &TokenStream::new(vec![tt.clone()]),
-                        true,
-                        sess,
-                        node_id,
-                        features,
-                        edition,
-                    )
-                    .pop()
-                    .unwrap();
-                    // We don't handle errors here, the driver will abort
-                    // after parsing/expansion. We can report every error in every macro this way.
-                    check_emission(check_lhs_nt_follows(sess, node_id, &tt));
-                    return tt;
-                }
-                sess.dcx().span_bug(span, "wrong-structured lhs")
-            })
-            .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.dcx().span_bug(span, "wrong-structured lhs"),
-    };
+    let mut lhses = Vec::new();
+    let mut rhses = Vec::new();
 
-    let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
-        MatchedSeq(s) => s
-            .iter()
-            .map(|m| {
-                if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
-                    return mbe::quoted::parse(
-                        &TokenStream::new(vec![tt.clone()]),
-                        false,
-                        sess,
-                        node_id,
-                        features,
-                        edition,
-                    )
-                    .pop()
-                    .unwrap();
-                }
-                sess.dcx().span_bug(span, "wrong-structured rhs")
-            })
-            .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.dcx().span_bug(span, "wrong-structured rhs"),
-    };
-
-    for rhs in &rhses {
-        check_emission(check_rhs(sess, rhs));
+    while p.token != token::Eof {
+        let lhs_tt = p.parse_token_tree();
+        let lhs_tt = mbe::quoted::parse(
+            &TokenStream::new(vec![lhs_tt]),
+            true, // LHS
+            sess,
+            node_id,
+            features,
+            edition,
+        )
+        .pop()
+        .unwrap();
+        // We don't handle errors here, the driver will abort after parsing/expansion. We can
+        // report every error in every macro this way.
+        check_emission(check_lhs_nt_follows(sess, node_id, &lhs_tt));
+        check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(&lhs_tt)));
+        if let Err(e) = p.expect(exp!(FatArrow)) {
+            return dummy_syn_ext(e.emit());
+        }
+        let rhs_tt = p.parse_token_tree();
+        let rhs_tt = mbe::quoted::parse(
+            &TokenStream::new(vec![rhs_tt]),
+            false, // RHS
+            sess,
+            node_id,
+            features,
+            edition,
+        )
+        .pop()
+        .unwrap();
+        check_emission(check_rhs(sess, &rhs_tt));
+        check_emission(macro_check::check_meta_variables(&sess.psess, node_id, &lhs_tt, &rhs_tt));
+        lhses.push(lhs_tt);
+        rhses.push(rhs_tt);
+        if p.token == token::Eof {
+            break;
+        }
+        if let Err(e) = p.expect(exp_sep) {
+            return dummy_syn_ext(e.emit());
+        }
     }
 
-    // Don't abort iteration early, so that errors for multiple lhses can be reported.
-    for lhs in &lhses {
-        check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs)));
+    if lhses.is_empty() {
+        let guar = sess.dcx().span_err(span, "macros must contain at least one rule");
+        return dummy_syn_ext(guar);
     }
 
-    check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses));
-
     let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
         .unwrap_or(Transparency::fallback(macro_rules));
 
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index af91c8b8f00..fd71f2ce948 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -681,7 +681,7 @@ impl server::Span for Rustc<'_, '_> {
             .lookup_char_pos(span.lo())
             .file
             .name
-            .prefer_remapped_unconditionaly()
+            .prefer_remapped_unconditionally()
             .to_string()
     }
 
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index db67c507b70..83be3241b12 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -265,6 +265,8 @@ declare_features! (
     (accepted, keylocker_x86, "1.89.0", Some(134813)),
     /// Allows `'a: { break 'a; }`.
     (accepted, label_break_value, "1.65.0", Some(48594)),
+    /// Allows `if/while p && let q = r && ...` chains.
+    (accepted, let_chains, "1.88.0", Some(53667)),
     /// Allows `let...else` statements.
     (accepted, let_else, "1.65.0", Some(87335)),
     /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 269a9c60d86..efd8bde71d7 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -550,8 +550,6 @@ declare_features! (
     (unstable, large_assignments, "1.52.0", Some(83518)),
     /// Allow to have type alias types for inter-crate use.
     (incomplete, lazy_type_alias, "1.72.0", Some(112792)),
-    /// Allows `if/while p && let q = r && ...` chains.
-    (unstable, let_chains, "1.37.0", Some(53667)),
     /// Allows using `#[link(kind = "link-arg", name = "...")]`
     /// to pass custom arguments to the linker.
     (unstable, link_arg_attribute, "1.76.0", Some(99427)),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c90cd93ff07..ca6405ea209 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -439,7 +439,7 @@ impl<'hir> ConstArg<'hir, AmbigArg> {
 }
 
 impl<'hir> ConstArg<'hir> {
-    /// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is
+    /// Converts a `ConstArg` in an unambiguous position to one in an ambiguous position. This is
     /// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions.
     ///
     /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if
@@ -508,7 +508,7 @@ pub enum GenericArg<'hir> {
     Lifetime(&'hir Lifetime),
     Type(&'hir Ty<'hir, AmbigArg>),
     Const(&'hir ConstArg<'hir, AmbigArg>),
-    /// Inference variables in [`GenericArg`] are always represnted by
+    /// Inference variables in [`GenericArg`] are always represented by
     /// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and
     /// [`ConstArgKind`] as it is not clear until hir ty lowering whether a
     /// `_` argument is a type or const argument.
@@ -3323,7 +3323,7 @@ impl<'hir> Ty<'hir, AmbigArg> {
 }
 
 impl<'hir> Ty<'hir> {
-    /// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is
+    /// Converts a `Ty` in an unambiguous position to one in an ambiguous position. This is
     /// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions.
     ///
     /// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if
@@ -4224,7 +4224,7 @@ impl fmt::Display for Constness {
     }
 }
 
-/// The actualy safety specified in syntax. We may treat
+/// The actual safety specified in syntax. We may treat
 /// its safety different within the type system to create a
 /// "sound by default" system that needs checking this enum
 /// explicitly to allow unsafe operations.
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 7eb896f0bf1..573af01a62d 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -1,12 +1,11 @@
 use std::assert_matches::assert_matches;
 use std::ops::ControlFlow;
 
-use hir::intravisit::{self, Visitor};
-use hir::{GenericParamKind, HirId, Node};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::VisitorExt;
-use rustc_hir::{self as hir, AmbigArg};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
+use rustc_hir::{self as hir, AmbigArg, GenericParamKind, HirId, Node};
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint;
 use rustc_span::{Span, Symbol, kw};
@@ -212,7 +211,19 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
             // inherit the generics of the item.
             Some(parent.to_def_id())
         }
-        _ => None,
+
+        // All of these nodes have no parent from which to inherit generics.
+        Node::Item(_) | Node::ForeignItem(_) => None,
+
+        // Params don't really have generics, but we use it when instantiating their value paths.
+        Node::GenericParam(_) => None,
+
+        Node::Synthetic => span_bug!(
+            tcx.def_span(def_id),
+            "synthetic HIR should have its `generics_of` explicitly fed"
+        ),
+
+        _ => span_bug!(tcx.def_span(def_id), "unhandled node {node:?}"),
     };
 
     enum Defaults {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 6b2854d96af..e13daabeb50 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1088,7 +1088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             // FIXME(#97583): Print associated item bindings properly (i.e., not as equality
             // predicates!).
-            // FIXME: Turn this into a structured, translateable & more actionable suggestion.
+            // FIXME: Turn this into a structured, translatable & more actionable suggestion.
             let mut where_bounds = vec![];
             for bound in [bound, bound2].into_iter().chain(matching_candidates) {
                 let bound_id = bound.def_id();
@@ -1588,7 +1588,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             &infcx_
         };
 
-        tcx.all_traits()
+        tcx.all_traits_including_private()
             .filter(|trait_def_id| {
                 // Consider only traits with the associated type
                 tcx.associated_items(*trait_def_id)
@@ -2459,13 +2459,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // type a projection.
                 let in_trait = match opaque_ty.origin {
                     hir::OpaqueTyOrigin::FnReturn {
+                        parent,
                         in_trait_or_impl: Some(hir::RpitContext::Trait),
                         ..
                     }
                     | hir::OpaqueTyOrigin::AsyncFn {
+                        parent,
                         in_trait_or_impl: Some(hir::RpitContext::Trait),
                         ..
-                    } => true,
+                    } => Some(parent),
                     hir::OpaqueTyOrigin::FnReturn {
                         in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
                         ..
@@ -2474,7 +2476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
                         ..
                     }
-                    | hir::OpaqueTyOrigin::TyAlias { .. } => false,
+                    | hir::OpaqueTyOrigin::TyAlias { .. } => None,
                 };
 
                 self.lower_opaque_ty(opaque_ty.def_id, in_trait)
@@ -2594,17 +2596,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
     /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
     #[instrument(level = "debug", skip(self), ret)]
-    fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
+    fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> {
         let tcx = self.tcx();
 
         let lifetimes = tcx.opaque_captured_lifetimes(def_id);
         debug!(?lifetimes);
 
-        // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
-        // generate the def_id of an associated type for the trait and return as
-        // type a projection.
-        let def_id = if in_trait {
-            tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id()
+        // If this is an RPITIT and we are using the new RPITIT lowering scheme,
+        // do a linear search to map this to the synthetic associated type that
+        // it will be lowered to.
+        let def_id = if let Some(parent_def_id) = in_trait {
+            *tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id)
+                .iter()
+                .find(|rpitit| match tcx.opt_rpitit_info(**rpitit) {
+                    Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
+                        opaque_def_id.expect_local() == def_id
+                    }
+                    _ => unreachable!(),
+                })
+                .unwrap()
         } else {
             def_id.to_def_id()
         };
@@ -2627,7 +2637,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         });
         debug!(?args);
 
-        if in_trait {
+        if in_trait.is_some() {
             Ty::new_projection_from_args(tcx, def_id, args)
         } else {
             Ty::new_opaque(tcx, def_id, args)
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 3ca04ba330b..b2a229ad651 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -726,7 +726,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 Err(SelectionError::TraitDynIncompatible(_)) => {
                     // Dyn compatibility errors in coercion will *always* be due to the
                     // fact that the RHS of the coercion is a non-dyn compatible `dyn Trait`
-                    // writen in source somewhere (otherwise we will never have lowered
+                    // written in source somewhere (otherwise we will never have lowered
                     // the dyn trait from HIR to middle).
                     //
                     // There's no reason to emit yet another dyn compatibility error,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 3c53a060f7f..eeb8d33ef65 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -121,7 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _ => {}
                 }
 
-                // We want to emit an error if the const is not structurally resolveable
+                // We want to emit an error if the const is not structurally resolvable
                 // as otherwise we can wind up conservatively proving `Copy` which may
                 // infer the repeat expr count to something that never required `Copy` in
                 // the first place.
@@ -2461,7 +2461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             spans.push_span_label(param.param.span(), "");
                         }
                     }
-                    // Highligh each parameter being depended on for a generic type.
+                    // Highlight each parameter being depended on for a generic type.
                     for ((&(_, param), deps), &(_, expected_ty)) in
                         params_with_generics.iter().zip(&dependants).zip(formal_and_expected_inputs)
                     {
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 9563cf734f6..4c343bb7c22 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -588,7 +588,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         let def_id = pick.item.def_id;
         let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args);
 
-        debug!("method_predicates after instantitation = {:?}", method_predicates);
+        debug!("method_predicates after instantiation = {:?}", method_predicates);
 
         let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args);
         debug!("type scheme instantiated, sig={:?}", sig);
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 085e7a2f5df..8380c3710e6 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // type parameters or early-bound regions.
         let tcx = self.tcx;
         // We use `Ident::with_dummy_span` since no built-in operator methods have
-        // any macro-specific hygeine, so the span's context doesn't really matter.
+        // any macro-specific hygiene, so the span's context doesn't really matter.
         let Some(method_item) =
             self.associated_value(trait_def_id, Ident::with_dummy_span(method_name))
         else {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index df1ee0e79c2..2815621ffde 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1725,7 +1725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if unsatisfied_predicates.is_empty()
                 // ...or if we already suggested that name because of `rustc_confusable` annotation
                 && Some(similar_candidate.name()) != confusable_suggested
-                // and if the we aren't in an expansion.
+                // and if we aren't in an expansion.
                 && !span.from_expansion()
             {
                 self.find_likely_intended_associated_item(
@@ -3481,9 +3481,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         err: &mut Diag<'_>,
         item_name: Ident,
-        valid_out_of_scope_traits: Vec<DefId>,
+        mut valid_out_of_scope_traits: Vec<DefId>,
         explain: bool,
     ) -> bool {
+        valid_out_of_scope_traits.retain(|id| self.tcx.is_user_visible_dep(id.krate));
         if !valid_out_of_scope_traits.is_empty() {
             let mut candidates = valid_out_of_scope_traits;
             candidates.sort_by_key(|id| self.tcx.def_path_str(id));
@@ -4388,7 +4389,7 @@ pub(crate) struct TraitInfo {
 /// Retrieves all traits in this crate and any dependent crates,
 /// and wraps them into `TraitInfo` for custom sorting.
 pub(crate) fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
-    tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect()
+    tcx.all_traits_including_private().map(|def_id| TraitInfo { def_id }).collect()
 }
 
 fn print_disambiguation_help<'tcx>(
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 349e72090d3..43475521a0f 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -723,7 +723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`.
             // In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`.
             | PatKind::Or(_)
-            // Like or-patterns, guard patterns just propogate to their subpatterns.
+            // Like or-patterns, guard patterns just propagate to their subpatterns.
             | PatKind::Guard(..) => AdjustMode::Pass,
         }
     }
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b2bd5e188ef..e30dbe80248 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -566,7 +566,7 @@ impl Cursor<'_> {
         }
 
         if !found {
-            // recovery strategy: a closing statement might have precending whitespace/newline
+            // recovery strategy: a closing statement might have preceding whitespace/newline
             // but not have enough dashes to properly close. In this case, we eat until there,
             // and report a mismatch in the parser.
             let mut rest = self.as_str();
diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs
index 845a1f1b81f..5490a3aac9b 100644
--- a/compiler/rustc_lint/src/autorefs.rs
+++ b/compiler/rustc_lint/src/autorefs.rs
@@ -41,7 +41,7 @@ declare_lint! {
     /// }
     /// ```
     ///
-    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// Otherwise try to find an alternative way to achieve your goals using only raw pointers:
     ///
     /// ```rust
     /// use std::ptr;
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 95663204ec3..b694d3dd49b 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -504,6 +504,7 @@ pub trait LintContext {
     ///
     /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
     #[rustc_lint_diagnostics]
+    #[track_caller]
     fn opt_span_lint<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -542,6 +543,7 @@ pub trait LintContext {
     ///
     /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
     #[rustc_lint_diagnostics]
+    #[track_caller]
     fn span_lint<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index 7734f441df2..0bc772d081f 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
             //     }
             // }
             // where `something()` would have to be a call or path.
-            // We have nothing meaninful to do with this.
+            // We have nothing meaningful to do with this.
             return;
         }
 
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index a9b04511c6b..263ea6fa070 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -230,7 +230,7 @@ impl IfLetRescope {
                     }
                 }
             }
-            // At this point, any `if let` fragment in the cascade is definitely preceeded by `else`,
+            // At this point, any `if let` fragment in the cascade is definitely preceded by `else`,
             // so a opening bracket is mandatory before each `match`.
             add_bracket_to_match_head = true;
             if let Some(alt) = alt {
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 1d4d380cb68..6ef9d4e9769 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
             let init = cx.expr_or_init(e);
             let orig_cast = if init.span != e.span { Some(init.span) } else { None };
 
-            // small cache to avoid recomputing needlesly computing peel_casts of init
+            // small cache to avoid recomputing needlessly computing peel_casts of init
             let mut peel_casts = {
                 let mut peel_casts_cache = None;
                 move || *peel_casts_cache.get_or_insert_with(|| peel_casts(cx, init))
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index a206f71e153..0627f70507c 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -3,6 +3,7 @@ use std::iter;
 use rustc_ast::util::{classify, parser};
 use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind};
 use rustc_attr_data_structures::{AttributeKind, find_attr};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{MultiSpan, pluralize};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -10,6 +11,7 @@ use rustc_hir::{self as hir, LangItem};
 use rustc_infer::traits::util::elaborate;
 use rustc_middle::ty::{self, Ty, adjustment};
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
+use rustc_span::edition::Edition::Edition2015;
 use rustc_span::{BytePos, Span, Symbol, kw, sym};
 use tracing::instrument;
 
@@ -1034,6 +1036,31 @@ pub(crate) struct UnusedParens {
     /// `1 as (i32) < 2` parses to ExprKind::Lt
     /// `1 as i32 < 2` parses to i32::<2[missing angle bracket]
     parens_in_cast_in_lt: Vec<ast::NodeId>,
+    /// Ty nodes in this map are in TypeNoBounds position. Any bounds they
+    /// contain may be ambiguous w/r/t trailing `+` operators.
+    in_no_bounds_pos: FxHashMap<ast::NodeId, NoBoundsException>,
+}
+
+/// Whether parentheses may be omitted from a type without resulting in ambiguity.
+///
+/// ```
+/// type Example = Box<dyn Fn() -> &'static (dyn Send) + Sync>;
+/// ```
+///
+/// Here, `&'static (dyn Send) + Sync` is a `TypeNoBounds`. As such, it may not directly
+/// contain `ImplTraitType` or `TraitObjectType` which is why `(dyn Send)` is parenthesized.
+/// However, an exception is made for `ImplTraitTypeOneBound` and `TraitObjectTypeOneBound`.
+/// The following is accepted because there is no `+`.
+///
+/// ```
+/// type Example = Box<dyn Fn() -> &'static dyn Send>;
+/// ```
+enum NoBoundsException {
+    /// The type must be parenthesized.
+    None,
+    /// The type is the last bound of the containing type expression. If it has exactly one bound,
+    /// parentheses around the type are unnecessary.
+    OneBound,
 }
 
 impl_lint_pass!(UnusedParens => [UNUSED_PARENS]);
@@ -1277,23 +1304,100 @@ impl EarlyLintPass for UnusedParens {
                 );
             }
             ast::TyKind::Paren(r) => {
-                match &r.kind {
-                    ast::TyKind::TraitObject(..) => {}
-                    ast::TyKind::BareFn(b)
-                        if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
-                    ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
-                    _ => {
-                        let spans = if !ty.span.from_expansion() {
+                let unused_parens = match &r.kind {
+                    ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _) => {
+                        match self.in_no_bounds_pos.get(&ty.id) {
+                            Some(NoBoundsException::None) => false,
+                            Some(NoBoundsException::OneBound) => bounds.len() <= 1,
+                            None => true,
+                        }
+                    }
+                    ast::TyKind::BareFn(b) => {
+                        !self.with_self_ty_parens || b.generic_params.is_empty()
+                    }
+                    _ => true,
+                };
+
+                if unused_parens {
+                    let spans = (!ty.span.from_expansion())
+                        .then(|| {
                             r.span
                                 .find_ancestor_inside(ty.span)
                                 .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
+                        })
+                        .flatten();
+
+                    self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
+                }
+
+                self.with_self_ty_parens = false;
+            }
+            ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => {
+                self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound);
+            }
+            ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
+                for i in 0..bounds.len() {
+                    let is_last = i == bounds.len() - 1;
+
+                    if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] {
+                        let fn_with_explicit_ret_ty = if let [.., segment] =
+                            &*poly_trait_ref.trait_ref.path.segments
+                            && let Some(args) = segment.args.as_ref()
+                            && let ast::GenericArgs::Parenthesized(paren_args) = &**args
+                            && let ast::FnRetTy::Ty(ret_ty) = &paren_args.output
+                        {
+                            self.in_no_bounds_pos.insert(
+                                ret_ty.id,
+                                if is_last {
+                                    NoBoundsException::OneBound
+                                } else {
+                                    NoBoundsException::None
+                                },
+                            );
+
+                            true
                         } else {
-                            None
+                            false
                         };
-                        self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
+
+                        // In edition 2015, dyn is a contextual keyword and `dyn::foo::Bar` is
+                        // parsed as a path, so parens are necessary to disambiguate. See
+                        //  - tests/ui/lint/unused/unused-parens-trait-obj-e2015.rs and
+                        //  - https://doc.rust-lang.org/reference/types/trait-object.html#r-type.trait-object.syntax-edition2018
+                        let dyn2015_exception = cx.sess().psess.edition == Edition2015
+                            && matches!(ty.kind, ast::TyKind::TraitObject(..))
+                            && i == 0
+                            && poly_trait_ref
+                                .trait_ref
+                                .path
+                                .segments
+                                .first()
+                                .map(|s| s.ident.name == kw::PathRoot)
+                                .unwrap_or(false);
+
+                        if let ast::Parens::Yes = poly_trait_ref.parens
+                            && (is_last || !fn_with_explicit_ret_ty)
+                            && !dyn2015_exception
+                        {
+                            let s = poly_trait_ref.span;
+                            let spans = (!s.from_expansion()).then(|| {
+                                (
+                                    s.with_hi(s.lo() + rustc_span::BytePos(1)),
+                                    s.with_lo(s.hi() - rustc_span::BytePos(1)),
+                                )
+                            });
+
+                            self.emit_unused_delims(
+                                cx,
+                                poly_trait_ref.span,
+                                spans,
+                                "type",
+                                (false, false),
+                                false,
+                            );
+                        }
                     }
                 }
-                self.with_self_ty_parens = false;
             }
             _ => {}
         }
@@ -1303,6 +1407,10 @@ impl EarlyLintPass for UnusedParens {
         <Self as UnusedDelimLint>::check_item(self, cx, item)
     }
 
+    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) {
+        self.in_no_bounds_pos.clear();
+    }
+
     fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
         use rustc_ast::{WhereBoundPredicate, WherePredicateKind};
         if let WherePredicateKind::BoundPredicate(WhereBoundPredicate {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 10ac14a2fbf..b37548b281c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1224,7 +1224,7 @@ declare_lint! {
     ///
     /// ### Explanation
     ///
-    /// A public `use` declaration should not be used to publicly re-export a
+    /// A public `use` declaration should not be used to publically re-export a
     /// private `extern crate`. `pub extern crate` should be used instead.
     ///
     /// This was historically allowed, but is not the intended behavior
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 42d006ef301..1006ea3ba10 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -177,7 +177,7 @@ decl_derive! {
     [PrintAttribute] =>
     /// Derives `PrintAttribute` for `AttributeKind`.
     /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in
-    /// other places. It's deriving something close to `Debug` without printing some extraenous
+    /// other places. It's deriving something close to `Debug` without printing some extraneous
     /// things like spans.
     print_attribute::print_attribute
 }
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 2196f71299a..5821ffa3a30 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -273,8 +273,8 @@ fn add_query_desc_cached_impl(
     // macro producing a higher order macro that has all its token in the macro declaration we lose
     // any meaningful spans, resulting in rust-analyzer being unable to make the connection between
     // the query name and the corresponding providers field. The trick to fix this is to have
-    // `rustc_queries` emit a field access with the given name's span which allows it to succesfully
-    // show references / go to definition to the correspondig provider assignment which is usually
+    // `rustc_queries` emit a field access with the given name's span which allows it to successfully
+    // show references / go to definition to the corresponding provider assignment which is usually
     // the more interesting place.
     let ra_hint = quote! {
         let crate::query::Providers { #name: _, .. };
@@ -413,7 +413,6 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
                 "Query {name} cannot be both `feedable` and `eval_always`."
             );
             feedable_queries.extend(quote! {
-                #(#doc_comments)*
                 [#attribute_stream] fn #name(#arg) #result,
             });
         }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 2c882b84c58..e65c7a68426 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -24,8 +24,7 @@ use rustc_middle::ty::data_structures::IndexSet;
 use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
 use rustc_proc_macro::bridge::client::ProcMacro;
 use rustc_session::config::{
-    self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers,
-    TargetModifier,
+    CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers, TargetModifier,
 };
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
 use rustc_session::lint::{self, BuiltinLintDiag};
@@ -33,11 +32,11 @@ use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_span::edition::Edition;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
-use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
+use rustc_target::spec::{PanicStrategy, Target};
 use tracing::{debug, info, trace};
 
 use crate::errors;
-use crate::locator::{CrateError, CrateLocator, CratePaths};
+use crate::locator::{CrateError, CrateLocator, CratePaths, CrateRejections};
 use crate::rmeta::{
     CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
 };
@@ -684,61 +683,67 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     fn load_proc_macro<'b>(
         &self,
         locator: &mut CrateLocator<'b>,
+        crate_rejections: &mut CrateRejections,
         path_kind: PathKind,
         host_hash: Option<Svh>,
     ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
     where
         'a: 'b,
     {
-        // Use a new crate locator so trying to load a proc macro doesn't affect the error
-        // message we emit
-        let mut proc_macro_locator = locator.clone();
-
-        // Try to load a proc macro
-        proc_macro_locator.is_proc_macro = true;
-
-        // Load the proc macro crate for the target
-        let (locator, target_result) = if self.sess.opts.unstable_opts.dual_proc_macros {
-            proc_macro_locator.reset();
-            let result = match self.load(&mut proc_macro_locator)? {
-                Some(LoadResult::Previous(cnum)) => {
-                    return Ok(Some((LoadResult::Previous(cnum), None)));
-                }
-                Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
-                None => return Ok(None),
-            };
-            locator.hash = host_hash;
-            // Use the locator when looking for the host proc macro crate, as that is required
-            // so we want it to affect the error message
-            (locator, result)
-        } else {
-            (&mut proc_macro_locator, None)
-        };
+        if self.sess.opts.unstable_opts.dual_proc_macros {
+            // Use a new crate locator and crate rejections so trying to load a proc macro doesn't
+            // affect the error message we emit
+            let mut proc_macro_locator = locator.clone();
+
+            // Try to load a proc macro
+            proc_macro_locator.for_target_proc_macro(self.sess, path_kind);
+
+            // Load the proc macro crate for the target
+            let target_result =
+                match self.load(&mut proc_macro_locator, &mut CrateRejections::default())? {
+                    Some(LoadResult::Previous(cnum)) => {
+                        return Ok(Some((LoadResult::Previous(cnum), None)));
+                    }
+                    Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
+                    None => return Ok(None),
+                };
 
-        // Load the proc macro crate for the host
+            // Use the existing crate_rejections as we want the error message to be affected by
+            // loading the host proc macro.
+            *crate_rejections = CrateRejections::default();
 
-        locator.reset();
-        locator.is_proc_macro = true;
-        locator.target = &self.sess.host;
-        locator.tuple = TargetTuple::from_tuple(config::host_tuple());
-        locator.filesearch = self.sess.host_filesearch();
-        locator.path_kind = path_kind;
+            // Load the proc macro crate for the host
+            locator.for_proc_macro(self.sess, path_kind);
 
-        let Some(host_result) = self.load(locator)? else {
-            return Ok(None);
-        };
+            locator.hash = host_hash;
+
+            let Some(host_result) = self.load(locator, crate_rejections)? else {
+                return Ok(None);
+            };
 
-        Ok(Some(if self.sess.opts.unstable_opts.dual_proc_macros {
             let host_result = match host_result {
                 LoadResult::Previous(..) => {
                     panic!("host and target proc macros must be loaded in lock-step")
                 }
                 LoadResult::Loaded(library) => library,
             };
-            (target_result.unwrap(), Some(host_result))
+            Ok(Some((target_result.unwrap(), Some(host_result))))
         } else {
-            (host_result, None)
-        }))
+            // Use a new crate locator and crate rejections so trying to load a proc macro doesn't
+            // affect the error message we emit
+            let mut proc_macro_locator = locator.clone();
+
+            // Load the proc macro crate for the host
+            proc_macro_locator.for_proc_macro(self.sess, path_kind);
+
+            let Some(host_result) =
+                self.load(&mut proc_macro_locator, &mut CrateRejections::default())?
+            else {
+                return Ok(None);
+            };
+
+            Ok(Some((host_result, None)))
+        }
     }
 
     fn resolve_crate(
@@ -799,15 +804,21 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 extra_filename,
                 path_kind,
             );
+            let mut crate_rejections = CrateRejections::default();
 
-            match self.load(&mut locator)? {
+            match self.load(&mut locator, &mut crate_rejections)? {
                 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)? {
+                    match self.load_proc_macro(
+                        &mut locator,
+                        &mut crate_rejections,
+                        path_kind,
+                        host_hash,
+                    )? {
                         Some(res) => res,
-                        None => return Err(locator.into_error(dep_root.cloned())),
+                        None => return Err(locator.into_error(crate_rejections, dep_root.cloned())),
                     }
                 }
             }
@@ -837,8 +848,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> {
-        let Some(library) = locator.maybe_load_library_crate()? else {
+    fn load(
+        &self,
+        locator: &CrateLocator<'_>,
+        crate_rejections: &mut CrateRejections,
+    ) -> Result<Option<LoadResult>, CrateError> {
+        let Some(library) = locator.maybe_load_library_crate(crate_rejections)? else {
             return Ok(None);
         };
 
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 941f16bd960..c30cfd1fcf7 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -224,11 +224,11 @@ use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
 use rustc_data_structures::svh::Svh;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_fs_util::try_canonicalize;
-use rustc_session::Session;
 use rustc_session::cstore::CrateSource;
 use rustc_session::filesearch::FileSearch;
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::CanonicalizedPath;
+use rustc_session::{Session, config};
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::{Target, TargetTuple};
 use tempfile::Builder as TempFileBuilder;
@@ -251,14 +251,11 @@ pub(crate) struct CrateLocator<'a> {
     exact_paths: Vec<CanonicalizedPath>,
     pub hash: Option<Svh>,
     extra_filename: Option<&'a str>,
-    pub target: &'a Target,
-    pub tuple: TargetTuple,
-    pub filesearch: &'a FileSearch,
-    pub is_proc_macro: bool,
-
-    pub path_kind: PathKind,
-    // Mutable in-progress state or output.
-    crate_rejections: CrateRejections,
+    target: &'a Target,
+    tuple: TargetTuple,
+    filesearch: &'a FileSearch,
+    is_proc_macro: bool,
+    path_kind: PathKind,
 }
 
 #[derive(Clone, Debug)]
@@ -346,34 +343,46 @@ impl<'a> CrateLocator<'a> {
             filesearch: sess.target_filesearch(),
             path_kind,
             is_proc_macro: false,
-            crate_rejections: CrateRejections::default(),
         }
     }
 
-    pub(crate) fn reset(&mut self) {
-        self.crate_rejections.via_hash.clear();
-        self.crate_rejections.via_triple.clear();
-        self.crate_rejections.via_kind.clear();
-        self.crate_rejections.via_version.clear();
-        self.crate_rejections.via_filename.clear();
-        self.crate_rejections.via_invalid.clear();
+    pub(crate) fn for_proc_macro(&mut self, sess: &'a Session, path_kind: PathKind) {
+        self.is_proc_macro = true;
+        self.target = &sess.host;
+        self.tuple = TargetTuple::from_tuple(config::host_tuple());
+        self.filesearch = sess.host_filesearch();
+        self.path_kind = path_kind;
     }
 
-    pub(crate) fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
+    pub(crate) fn for_target_proc_macro(&mut self, sess: &'a Session, path_kind: PathKind) {
+        self.is_proc_macro = true;
+        self.target = &sess.target;
+        self.tuple = sess.opts.target_triple.clone();
+        self.filesearch = sess.target_filesearch();
+        self.path_kind = path_kind;
+    }
+
+    pub(crate) fn maybe_load_library_crate(
+        &self,
+        crate_rejections: &mut CrateRejections,
+    ) -> Result<Option<Library>, CrateError> {
         if !self.exact_paths.is_empty() {
-            return self.find_commandline_library();
+            return self.find_commandline_library(crate_rejections);
         }
         let mut seen_paths = FxHashSet::default();
         if let Some(extra_filename) = self.extra_filename {
-            if let library @ Some(_) = self.find_library_crate(extra_filename, &mut seen_paths)? {
+            if let library @ Some(_) =
+                self.find_library_crate(crate_rejections, extra_filename, &mut seen_paths)?
+            {
                 return Ok(library);
             }
         }
-        self.find_library_crate("", &mut seen_paths)
+        self.find_library_crate(crate_rejections, "", &mut seen_paths)
     }
 
     fn find_library_crate(
-        &mut self,
+        &self,
+        crate_rejections: &mut CrateRejections,
         extra_prefix: &str,
         seen_paths: &mut FxHashSet<PathBuf>,
     ) -> Result<Option<Library>, CrateError> {
@@ -437,8 +446,8 @@ impl<'a> CrateLocator<'a> {
                         let (rlibs, rmetas, dylibs, interfaces) =
                             candidates.entry(hash).or_default();
                         {
-                            // As a perforamnce optimisation we canonicalize the path and skip
-                            // ones we've already seeen. This allows us to ignore crates
+                            // As a performance optimisation we canonicalize the path and skip
+                            // ones we've already seen. This allows us to ignore crates
                             // we know are exactual equal to ones we've already found.
                             // Going to the same crate through different symlinks does not change the result.
                             let path = try_canonicalize(&spf.path)
@@ -465,7 +474,7 @@ impl<'a> CrateLocator<'a> {
                 .flatten()
             {
                 for (_, spf) in static_matches {
-                    self.crate_rejections.via_kind.push(CrateMismatch {
+                    crate_rejections.via_kind.push(CrateMismatch {
                         path: spf.path.to_path_buf(),
                         got: "static".to_string(),
                     });
@@ -483,7 +492,9 @@ impl<'a> CrateLocator<'a> {
         // search is being performed for.
         let mut libraries = FxIndexMap::default();
         for (_hash, (rlibs, rmetas, dylibs, interfaces)) in candidates {
-            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs, interfaces)? {
+            if let Some((svh, lib)) =
+                self.extract_lib(crate_rejections, rlibs, rmetas, dylibs, interfaces)?
+            {
                 libraries.insert(svh, lib);
             }
         }
@@ -495,13 +506,11 @@ impl<'a> CrateLocator<'a> {
             0 => Ok(None),
             1 => Ok(Some(libraries.into_iter().next().unwrap().1)),
             _ => {
-                let mut libraries: Vec<_> = libraries.into_values().collect();
-
-                libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
-                let candidates = libraries
-                    .iter()
+                let mut candidates: Vec<PathBuf> = libraries
+                    .into_values()
                     .map(|lib| lib.source.paths().next().unwrap().clone())
-                    .collect::<Vec<_>>();
+                    .collect();
+                candidates.sort();
 
                 Err(CrateError::MultipleCandidates(
                     self.crate_name,
@@ -514,7 +523,8 @@ impl<'a> CrateLocator<'a> {
     }
 
     fn extract_lib(
-        &mut self,
+        &self,
+        crate_rejections: &mut CrateRejections,
         rlibs: FxIndexMap<PathBuf, PathKind>,
         rmetas: FxIndexMap<PathBuf, PathKind>,
         dylibs: FxIndexMap<PathBuf, PathKind>,
@@ -526,10 +536,11 @@ impl<'a> CrateLocator<'a> {
         // Make sure there's at most one rlib and at most one dylib.
         //
         // See comment in `extract_one` below.
-        let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?;
-        let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?;
-        let sdylib_interface = self.extract_one(interfaces, CrateFlavor::SDylib, &mut slot)?;
-        let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?;
+        let rmeta = self.extract_one(crate_rejections, rmetas, CrateFlavor::Rmeta, &mut slot)?;
+        let rlib = self.extract_one(crate_rejections, rlibs, CrateFlavor::Rlib, &mut slot)?;
+        let sdylib_interface =
+            self.extract_one(crate_rejections, interfaces, CrateFlavor::SDylib, &mut slot)?;
+        let dylib = self.extract_one(crate_rejections, dylibs, CrateFlavor::Dylib, &mut slot)?;
 
         if sdylib_interface.is_some() && dylib.is_none() {
             return Err(CrateError::FullMetadataNotFound(self.crate_name, CrateFlavor::SDylib));
@@ -563,7 +574,8 @@ impl<'a> CrateLocator<'a> {
     //
     // The `PathBuf` in `slot` will only be used for diagnostic purposes.
     fn extract_one(
-        &mut self,
+        &self,
+        crate_rejections: &mut CrateRejections,
         m: FxIndexMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
         slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>,
@@ -605,7 +617,7 @@ impl<'a> CrateLocator<'a> {
                 Some(self.crate_name),
             ) {
                 Ok(blob) => {
-                    if let Some(h) = self.crate_matches(&blob, &lib) {
+                    if let Some(h) = self.crate_matches(crate_rejections, &blob, &lib) {
                         (h, blob)
                     } else {
                         info!("metadata mismatch");
@@ -620,7 +632,7 @@ impl<'a> CrateLocator<'a> {
                         "Rejecting via version: expected {} got {}",
                         expected_version, found_version
                     );
-                    self.crate_rejections
+                    crate_rejections
                         .via_version
                         .push(CrateMismatch { path: lib, got: found_version });
                     continue;
@@ -635,7 +647,7 @@ impl<'a> CrateLocator<'a> {
                     // The file was present and created by the same compiler version, but we
                     // couldn't load it for some reason. Give a hard error instead of silently
                     // ignoring it, but only if we would have given an error anyway.
-                    self.crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err });
+                    crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err });
                     continue;
                 }
                 Err(err @ MetadataError::NotPresent(_)) => {
@@ -713,7 +725,12 @@ impl<'a> CrateLocator<'a> {
         }
     }
 
-    fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
+    fn crate_matches(
+        &self,
+        crate_rejections: &mut CrateRejections,
+        metadata: &MetadataBlob,
+        libpath: &Path,
+    ) -> Option<Svh> {
         let header = metadata.get_header();
         if header.is_proc_macro_crate != self.is_proc_macro {
             info!(
@@ -730,7 +747,7 @@ impl<'a> CrateLocator<'a> {
 
         if header.triple != self.tuple {
             info!("Rejecting via crate triple: expected {} got {}", self.tuple, header.triple);
-            self.crate_rejections.via_triple.push(CrateMismatch {
+            crate_rejections.via_triple.push(CrateMismatch {
                 path: libpath.to_path_buf(),
                 got: header.triple.to_string(),
             });
@@ -741,7 +758,7 @@ impl<'a> CrateLocator<'a> {
         if let Some(expected_hash) = self.hash {
             if hash != expected_hash {
                 info!("Rejecting via hash: expected {} got {}", expected_hash, hash);
-                self.crate_rejections
+                crate_rejections
                     .via_hash
                     .push(CrateMismatch { path: libpath.to_path_buf(), got: hash.to_string() });
                 return None;
@@ -751,7 +768,10 @@ impl<'a> CrateLocator<'a> {
         Some(hash)
     }
 
-    fn find_commandline_library(&mut self) -> Result<Option<Library>, CrateError> {
+    fn find_commandline_library(
+        &self,
+        crate_rejections: &mut CrateRejections,
+    ) -> Result<Option<Library>, CrateError> {
         // First, filter out all libraries that look suspicious. We only accept
         // files which actually exist that have the correct naming scheme for
         // rlibs/dylibs.
@@ -796,24 +816,28 @@ impl<'a> CrateLocator<'a> {
                 dylibs.insert(loc_canon.clone(), PathKind::ExternFlag);
                 continue;
             }
-            self.crate_rejections
+            crate_rejections
                 .via_filename
                 .push(CrateMismatch { path: loc_orig.clone(), got: String::new() });
         }
 
         // Extract the dylib/rlib/rmeta triple.
-        self.extract_lib(rlibs, rmetas, dylibs, sdylib_interfaces)
+        self.extract_lib(crate_rejections, rlibs, rmetas, dylibs, sdylib_interfaces)
             .map(|opt| opt.map(|(_, lib)| lib))
     }
 
-    pub(crate) fn into_error(self, dep_root: Option<CratePaths>) -> CrateError {
+    pub(crate) fn into_error(
+        self,
+        crate_rejections: CrateRejections,
+        dep_root: Option<CratePaths>,
+    ) -> CrateError {
         CrateError::LocatorCombined(Box::new(CombinedLocatorError {
             crate_name: self.crate_name,
             dep_root,
             triple: self.tuple,
             dll_prefix: self.target.dll_prefix.to_string(),
             dll_suffix: self.target.dll_suffix.to_string(),
-            crate_rejections: self.crate_rejections,
+            crate_rejections,
         }))
     }
 }
@@ -993,7 +1017,7 @@ struct CrateMismatch {
 }
 
 #[derive(Clone, Debug, Default)]
-struct CrateRejections {
+pub(crate) struct CrateRejections {
     via_hash: Vec<CrateMismatch>,
     via_triple: Vec<CrateMismatch>,
     via_kind: Vec<CrateMismatch>,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 4198b198ab1..d2cadc96b63 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -799,7 +799,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
     /// Initialize all previously uninitialized bytes in the entire allocation, and set
     /// provenance of everything to `Wildcard`. Before calling this, make sure all
     /// provenance in this allocation is exposed!
-    pub fn prepare_for_native_write(&mut self) -> AllocResult {
+    pub fn prepare_for_native_access(&mut self) {
         let full_range = AllocRange { start: Size::ZERO, size: Size::from_bytes(self.len()) };
         // Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be.
         for chunk in self.init_mask.range_as_init_chunks(full_range) {
@@ -814,13 +814,6 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
 
         // Set provenance of all bytes to wildcard.
         self.provenance.write_wildcards(self.len());
-
-        // Also expose the provenance of the interpreter-level allocation, so it can
-        // be written by FFI. The `black_box` is defensive programming as LLVM likes
-        // to (incorrectly) optimize away ptr2int casts whose result is unused.
-        std::hint::black_box(self.get_bytes_unchecked_raw_mut().expose_provenance());
-
-        Ok(())
     }
 
     /// Remove all provenance in the given memory range.
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index c9525df1f79..63608947eb3 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -120,7 +120,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
         }
     }
 
-    /// Check if here is ptr-sized provenance at the given index.
+    /// Check if there is ptr-sized provenance at the given index.
     /// Does not mean anything for bytewise provenance! But can be useful as an optimization.
     pub fn get_ptr(&self, offset: Size) -> Option<Prov> {
         self.ptrs.get(&offset).copied()
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 41a166083d0..8acb8fa9f80 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -116,7 +116,7 @@ impl<'tcx> From<ErrorHandled> for ValTreeCreationError<'tcx> {
 
 impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
     fn from(err: InterpErrorInfo<'tcx>) -> Self {
-        // An error ocurred outside the const-eval query, as part of constructing the valtree. We
+        // An error occurred outside the const-eval query, as part of constructing the valtree. We
         // don't currently preserve the details of this error, since `InterpErrorInfo` cannot be put
         // into a query result and it can only be access of some mutable or external memory.
         let (_kind, backtrace) = err.into_parts();
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 33e97766a02..e819aa2d8f8 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -262,7 +262,7 @@ pub struct Body<'tcx> {
     /// us to see the difference and forego optimization on the inlined promoted items.
     pub phase: MirPhase,
 
-    /// How many passses we have executed since starting the current phase. Used for debug output.
+    /// How many passes we have executed since starting the current phase. Used for debug output.
     pub pass_count: usize,
 
     pub source: MirSource<'tcx>,
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 92eefd89848..6039a03aa29 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -381,7 +381,7 @@ pub enum StatementKind<'tcx> {
     /// computing these locals.
     ///
     /// If the local is already allocated, calling `StorageLive` again will implicitly free the
-    /// local and then allocate fresh uninitilized memory. If a local is already deallocated,
+    /// local and then allocate fresh uninitialized memory. If a local is already deallocated,
     /// calling `StorageDead` again is a NOP.
     StorageLive(Local),
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 3e68f0f784e..8c20e71e26a 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -355,7 +355,7 @@ rustc_queries! {
     /// Returns whether the type alias given by `DefId` is lazy.
     ///
     /// I.e., if the type alias expands / ought to expand to a [free] [alias type]
-    /// instead of the underyling aliased type.
+    /// instead of the underlying aliased type.
     ///
     /// Relevant for features `lazy_type_alias` and `type_alias_impl_trait`.
     ///
@@ -440,7 +440,6 @@ rustc_queries! {
     query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
-        feedable
     }
 
     query opaque_types_defined_by(
@@ -1093,13 +1092,6 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
-    /// associated item.
-    query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
-        desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) }
-        cache_on_disk_if { true }
-    }
-
     /// Given an `impl_id`, return the trait it implements along with some header information.
     /// Return `None` if this is an inherent impl.
     query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index bda8dcadbce..730c1147684 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -380,11 +380,11 @@ pub enum ExprKind<'tcx> {
     },
     /// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression.
     LoopMatch {
-        /// The state variable that is updated, and also the scrutinee of the match.
+        /// The state variable that is updated.
+        /// The `match_data.scrutinee` is the same variable, but with a different span.
         state: ExprId,
         region_scope: region::Scope,
-        arms: Box<[ArmId]>,
-        match_span: Span,
+        match_data: Box<LoopMatchMatchData>,
     },
     /// Special expression representing the `let` part of an `if let` or similar construct
     /// (including `if let` guards in match arms, and let-chains formed by `&&`).
@@ -599,6 +599,14 @@ pub struct Arm<'tcx> {
     pub span: Span,
 }
 
+/// The `match` part of a `#[loop_match]`
+#[derive(Clone, Debug, HashStable)]
+pub struct LoopMatchMatchData {
+    pub scrutinee: ExprId,
+    pub arms: Box<[ArmId]>,
+    pub span: Span,
+}
+
 #[derive(Copy, Clone, Debug, HashStable)]
 pub enum LogicalOp {
     /// The `&&` operator.
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index c9ef723aea4..dcfa6c4db32 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -2,6 +2,7 @@ use super::{
     AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand,
     Pat, PatKind, Stmt, StmtKind, Thir,
 };
+use crate::thir::LoopMatchMatchData;
 
 /// Every `walk_*` method uses deconstruction to access fields of structs and
 /// enums. This will result in a compile error if a field is added, which makes
@@ -83,7 +84,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
             visitor.visit_pat(pat);
         }
         Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
-        LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => {
+        LoopMatch { match_data: box LoopMatchMatchData { scrutinee, ref arms, .. }, .. }
+        | Match { scrutinee, ref arms, .. } => {
             visitor.visit_expr(&visitor.thir()[scrutinee]);
             for &arm in &**arms {
                 visitor.visit_arm(&visitor.thir()[arm]);
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f5c55f96875..efa47b57cf3 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2287,7 +2287,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     /// All traits in the crate graph, including those not visible to the user.
-    pub fn all_traits(self) -> impl Iterator<Item = DefId> {
+    pub fn all_traits_including_private(self) -> impl Iterator<Item = DefId> {
         iter::once(LOCAL_CRATE)
             .chain(self.crates(()).iter().copied())
             .flat_map(move |cnum| self.traits(cnum).iter().copied())
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 68adfb3cdb3..21b7500e46f 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> {
     /// - coroutines
     Item(DefId),
 
-    /// An intrinsic `fn` item (with`#[rustc_instrinsic]`).
+    /// An intrinsic `fn` item (with`#[rustc_intrinsic]`).
     ///
     /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR.
     /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the
@@ -445,10 +445,10 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
     }
 }
 
-// async_drop_in_place<T>::coroutine.poll, when T is a standart coroutine,
+// async_drop_in_place<T>::coroutine.poll, when T is a standard coroutine,
 // should be resolved to this coroutine's future_drop_poll (through FutureDropPollShim proxy).
 // async_drop_in_place<async_drop_in_place<T>::coroutine>::coroutine.poll,
-// when T is a standart coroutine, should be resolved to this coroutine's future_drop_poll.
+// when T is a standard coroutine, should be resolved to this coroutine's future_drop_poll.
 // async_drop_in_place<async_drop_in_place<T>::coroutine>::coroutine.poll,
 // when T is not a coroutine, should be resolved to the innermost
 // async_drop_in_place<T>::coroutine's poll function (through FutureDropPollShim proxy)
diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs
index 561f84192b4..5ada9ecc80c 100644
--- a/compiler/rustc_middle/src/ty/significant_drop_order.rs
+++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs
@@ -70,7 +70,7 @@ fn true_significant_drop_ty<'tcx>(
     }
 }
 
-/// Returns the list of types with a "potentially sigificant" that may be dropped
+/// Returns the list of types with a "potentially significant" that may be dropped
 /// by dropping a value of type `ty`.
 #[instrument(level = "trace", skip(tcx, typing_env))]
 pub fn extract_component_raw<'tcx>(
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 399a6d6ebc5..7a1890226c9 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1676,7 +1676,7 @@ impl<'tcx> Ty<'tcx> {
     /// This is particularly useful for getting the type of the result of
     /// [`UnOp::PtrMetadata`](crate::mir::UnOp::PtrMetadata).
     ///
-    /// Panics if `self` is not dereferencable.
+    /// Panics if `self` is not dereferenceable.
     #[track_caller]
     pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         let Some(pointee_ty) = self.builtin_deref(true) else {
diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs
index fe3d072fa88..82b883a99a1 100644
--- a/compiler/rustc_mir_build/src/builder/expr/into.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/into.rs
@@ -245,7 +245,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     None
                 })
             }
-            ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => {
+            ExprKind::LoopMatch {
+                state,
+                region_scope,
+                match_data: box LoopMatchMatchData { box ref arms, span: match_span, scrutinee },
+            } => {
                 // Intuitively, this is a combination of a loop containing a labeled block
                 // containing a match.
                 //
@@ -292,8 +296,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     // Logic for `match`.
                     let scrutinee_place_builder =
-                        unpack!(body_block = this.as_place_builder(body_block, state));
-                    let scrutinee_span = this.thir.exprs[state].span;
+                        unpack!(body_block = this.as_place_builder(body_block, scrutinee));
+                    let scrutinee_span = this.thir.exprs[scrutinee].span;
                     let match_start_span = match_span.shrink_to_lo().to(scrutinee_span);
 
                     let mut patterns = Vec::with_capacity(arms.len());
@@ -335,7 +339,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             move |this| {
                                 this.in_breakable_scope(None, state_place, expr_span, |this| {
                                     Some(this.in_const_continuable_scope(
-                                        arms.clone(),
+                                        Box::from(arms),
                                         built_tree.clone(),
                                         state_place,
                                         expr_span,
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index 9600067a85f..2c29b862841 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -2970,6 +2970,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             Constructor::Wildcard => true,
 
+            // Opaque patterns must not be matched on structurally.
+            Constructor::Opaque(_) => false,
+
             // These we may eventually support:
             Constructor::Struct
             | Constructor::Ref
@@ -2980,8 +2983,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()),
 
             // These should never occur here:
-            Constructor::Opaque(_)
-            | Constructor::Never
+            Constructor::Never
             | Constructor::NonExhaustive
             | Constructor::Hidden
             | Constructor::Missing
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 20e836f6bf2..16b49bf384c 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1230,7 +1230,6 @@ pub(crate) struct ConstContinueMissingValue {
 
 #[derive(Diagnostic)]
 #[diag(mir_build_const_continue_unknown_jump_target)]
-#[note]
 pub(crate) struct ConstContinueUnknownJumpTarget {
     #[primary_span]
     pub 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 5197e93fda7..b694409f327 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -983,8 +983,11 @@ impl<'tcx> ThirBuildCx<'tcx> {
                             data: region::ScopeData::Node,
                         },
 
-                        arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
-                        match_span: block_body_expr.span,
+                        match_data: Box::new(LoopMatchMatchData {
+                            scrutinee: self.mirror_expr(scrutinee),
+                            arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
+                            span: block_body_expr.span,
+                        }),
                     }
                 } else {
                     let block_ty = self.typeck_results.node_type(body.hir_id);
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 41fbabc2539..b7b160c738d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -6,7 +6,7 @@ use rustc_errors::codes::*;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err};
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
+use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::Level;
 use rustc_middle::bug;
@@ -154,6 +154,12 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
             ExprKind::Match { scrutinee, box ref arms, match_source } => {
                 self.check_match(scrutinee, arms, match_source, ex.span);
             }
+            ExprKind::LoopMatch {
+                match_data: box LoopMatchMatchData { scrutinee, box ref arms, span },
+                ..
+            } => {
+                self.check_match(scrutinee, arms, MatchSource::Normal, span);
+            }
             ExprKind::Let { box ref pat, expr } => {
                 self.check_let(pat, Some(expr), ex.span);
             }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 003ad170861..6d617d43c2a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -365,11 +365,11 @@ fn extend_type_not_partial_eq<'tcx>(
     struct UsedParamsNeedInstantiationVisitor<'tcx> {
         tcx: TyCtxt<'tcx>,
         typing_env: ty::TypingEnv<'tcx>,
-        /// The user has written `impl PartialEq for Ty` which means it's non-structual.
+        /// The user has written `impl PartialEq for Ty` which means it's non-structural.
         adts_with_manual_partialeq: FxHashSet<Span>,
         /// The type has no `PartialEq` implementation, neither manual or derived.
         adts_without_partialeq: FxHashSet<Span>,
-        /// The user has written `impl PartialEq for Ty` which means it's non-structual,
+        /// The user has written `impl PartialEq for Ty` which means it's non-structural,
         /// but we don't have a span to point at, so we'll just add them as a `note`.
         manual: FxHashSet<Ty<'tcx>>,
         /// The type has no `PartialEq` implementation, neither manual or derived, but
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 1507b6b8c06..5efc4be2de2 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -318,18 +318,23 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_expr(*body, depth_lvl + 2);
                 print_indented!(self, ")", depth_lvl);
             }
-            LoopMatch { state, region_scope, match_span, arms } => {
+            LoopMatch { state, region_scope, match_data } => {
                 print_indented!(self, "LoopMatch {", depth_lvl);
                 print_indented!(self, "state:", depth_lvl + 1);
                 self.print_expr(*state, depth_lvl + 2);
                 print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
-                print_indented!(self, format!("match_span: {:?}", match_span), depth_lvl + 1);
-
-                print_indented!(self, "arms: [", depth_lvl + 1);
-                for arm_id in arms.iter() {
-                    self.print_arm(*arm_id, depth_lvl + 2);
+                print_indented!(self, "match_data:", depth_lvl + 1);
+                print_indented!(self, "LoopMatchMatchData {", depth_lvl + 2);
+                print_indented!(self, format!("span: {:?}", match_data.span), depth_lvl + 3);
+                print_indented!(self, "scrutinee:", depth_lvl + 3);
+                self.print_expr(match_data.scrutinee, depth_lvl + 4);
+
+                print_indented!(self, "arms: [", depth_lvl + 3);
+                for arm_id in match_data.arms.iter() {
+                    self.print_arm(*arm_id, depth_lvl + 4);
                 }
-                print_indented!(self, "]", depth_lvl + 1);
+                print_indented!(self, "]", depth_lvl + 3);
+                print_indented!(self, "}", depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl);
             }
             Let { expr, pat } => {
diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs
index 240da87ab27..33a87cb9873 100644
--- a/compiler/rustc_mir_transform/src/check_enums.rs
+++ b/compiler/rustc_mir_transform/src/check_enums.rs
@@ -120,6 +120,7 @@ enum EnumCheckType<'tcx> {
     },
 }
 
+#[derive(Debug, Copy, Clone)]
 struct TyAndSize<'tcx> {
     pub ty: Ty<'tcx>,
     pub size: Size,
@@ -310,7 +311,7 @@ fn insert_discr_cast_to_u128<'tcx>(
         StatementKind::Assign(Box::new((discr_in_discr_ty, rvalue))),
     ));
 
-    // Cast the discriminant to a u128 (base for comparisions of enum discriminants).
+    // Cast the discriminant to a u128 (base for comparisons of enum discriminants).
     let const_u128 = Ty::new_uint(tcx, ty::UintTy::U128);
     let rvalue = Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr_in_discr_ty), const_u128);
     let discr = local_decls.push(LocalDecl::with_source_info(const_u128, source_info)).into();
@@ -337,7 +338,7 @@ fn insert_direct_enum_check<'tcx>(
     let invalid_discr_block_data = BasicBlockData::new(None, false);
     let invalid_discr_block = basic_blocks.push(invalid_discr_block_data);
     let block_data = &mut basic_blocks[current_block];
-    let discr = insert_discr_cast_to_u128(
+    let discr_place = insert_discr_cast_to_u128(
         tcx,
         local_decls,
         block_data,
@@ -348,13 +349,34 @@ fn insert_direct_enum_check<'tcx>(
         source_info,
     );
 
+    // Mask out the bits of the discriminant type.
+    let mask = discr.size.unsigned_int_max();
+    let discr_masked =
+        local_decls.push(LocalDecl::with_source_info(tcx.types.u128, source_info)).into();
+    let rvalue = Rvalue::BinaryOp(
+        BinOp::BitAnd,
+        Box::new((
+            Operand::Copy(discr_place),
+            Operand::Constant(Box::new(ConstOperand {
+                span: source_info.span,
+                user_ty: None,
+                const_: Const::Val(ConstValue::from_u128(mask), tcx.types.u128),
+            })),
+        )),
+    );
+    block_data
+        .statements
+        .push(Statement::new(source_info, StatementKind::Assign(Box::new((discr_masked, rvalue)))));
+
     // Branch based on the discriminant value.
     block_data.terminator = Some(Terminator {
         source_info,
         kind: TerminatorKind::SwitchInt {
-            discr: Operand::Copy(discr),
+            discr: Operand::Copy(discr_masked),
             targets: SwitchTargets::new(
-                discriminants.into_iter().map(|discr| (discr, new_block)),
+                discriminants
+                    .into_iter()
+                    .map(|discr_val| (discr.size.truncate(discr_val), new_block)),
                 invalid_discr_block,
             ),
         },
@@ -371,7 +393,7 @@ fn insert_direct_enum_check<'tcx>(
             })),
             expected: true,
             target: new_block,
-            msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr))),
+            msg: Box::new(AssertKind::InvalidEnumConstruction(Operand::Copy(discr_masked))),
             // This calls panic_invalid_enum_construction, which is #[rustc_nounwind].
             // We never want to insert an unwind into unsafe code, because unwinding could
             // make a failing UB check turn into much worse UB when we start unwinding.
@@ -445,7 +467,7 @@ fn insert_niche_check<'tcx>(
         source_info,
     );
 
-    // Compare the discriminant agains the valid_range.
+    // Compare the discriminant against the valid_range.
     let start_const = Operand::Constant(Box::new(ConstOperand {
         span: source_info.span,
         user_ty: None,
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 0a839d91404..81d7b7ba02c 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -239,7 +239,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
     body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id));
     body_def.generics_of(tcx.generics_of(coroutine_def_id).clone());
     body_def.param_env(tcx.param_env(coroutine_def_id));
-    body_def.predicates_of(tcx.predicates_of(coroutine_def_id));
+    body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id));
 
     // The type of the coroutine is the `by_move_coroutine_ty`.
     body_def.type_of(ty::EarlyBinder::bind(by_move_coroutine_ty));
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 335354c23b6..6b11706d2b5 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -29,7 +29,7 @@
 //! _b = some other value // also has VnIndex i
 //! ```
 //!
-//! We consider it to be replacable by:
+//! We consider it to be replaceable by:
 //! ```ignore (MIR)
 //! _a = some value // has VnIndex i
 //! // some MIR
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 7852bb7ae2f..1c0fc774867 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -982,14 +982,16 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
     // Insert all of the (mapped) parts of the callee body into the caller.
     caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
     caller_body.source_scopes.append(&mut callee_body.source_scopes);
+
+    // only "full" debug promises any variable-level information
     if tcx
         .sess
         .opts
         .unstable_opts
         .inline_mir_preserve_debug
-        .unwrap_or(tcx.sess.opts.debuginfo != DebugInfo::None)
+        .unwrap_or(tcx.sess.opts.debuginfo == DebugInfo::Full)
     {
-        // Note that we need to preserve these in the standard library so that
+        // -Zinline-mir-preserve-debug is enabled when building the standard library, so that
         // people working on rust can build with or without debuginfo while
         // still getting consistent results from the mir-opt tests.
         caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
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
index 1bd770a8526..2f0edf31162 100644
--- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -516,7 +516,7 @@ struct LocalLabel<'a> {
 /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order
 impl Subdiagnostic for LocalLabel<'_> {
     fn add_to_diag<G: rustc_errors::EmissionGuarantee>(self, diag: &mut rustc_errors::Diag<'_, G>) {
-        // Becuase parent uses this field , we need to remove it delay before adding it.
+        // Because parent uses this field , we need to remove it delay before adding it.
         diag.remove_arg("name");
         diag.arg("name", self.name);
         diag.remove_arg("is_generated_name");
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 368d5340ac3..d1c2d6b508f 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -138,7 +138,7 @@ fn compute_replacement<'tcx>(
     // reborrowed references.
     let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len());
 
-    let fully_replacable_locals = fully_replacable_locals(ssa);
+    let fully_replaceable_locals = fully_replaceable_locals(ssa);
 
     // Returns true iff we can use `place` as a pointee.
     //
@@ -204,7 +204,7 @@ fn compute_replacement<'tcx>(
         let needs_unique = ty.is_mutable_ptr();
 
         // If this a mutable reference that we cannot fully replace, mark it as unknown.
-        if needs_unique && !fully_replacable_locals.contains(local) {
+        if needs_unique && !fully_replaceable_locals.contains(local) {
             debug!("not fully replaceable");
             continue;
         }
@@ -303,7 +303,7 @@ fn compute_replacement<'tcx>(
 
                     // This a reborrow chain, recursively allow the replacement.
                     //
-                    // This also allows to detect cases where `target.local` is not replacable,
+                    // This also allows to detect cases where `target.local` is not replaceable,
                     // and mark it as such.
                     if let &[PlaceElem::Deref] = &target.projection[..] {
                         assert!(perform_opt);
@@ -313,7 +313,7 @@ fn compute_replacement<'tcx>(
                     } else if perform_opt {
                         self.allowed_replacements.insert((target.local, loc));
                     } else if needs_unique {
-                        // This mutable reference is not fully replacable, so drop it.
+                        // This mutable reference is not fully replaceable, so drop it.
                         self.targets[place.local] = Value::Unknown;
                     }
                 }
@@ -326,22 +326,22 @@ fn compute_replacement<'tcx>(
 
 /// Compute the set of locals that can be fully replaced.
 ///
-/// We consider a local to be replacable iff it's only used in a `Deref` projection `*_local` or
+/// We consider a local to be replaceable iff it's only used in a `Deref` projection `*_local` or
 /// non-use position (like storage statements and debuginfo).
-fn fully_replacable_locals(ssa: &SsaLocals) -> DenseBitSet<Local> {
-    let mut replacable = DenseBitSet::new_empty(ssa.num_locals());
+fn fully_replaceable_locals(ssa: &SsaLocals) -> DenseBitSet<Local> {
+    let mut replaceable = DenseBitSet::new_empty(ssa.num_locals());
 
     // First pass: for each local, whether its uses can be fully replaced.
     for local in ssa.locals() {
         if ssa.num_direct_uses(local) == 0 {
-            replacable.insert(local);
+            replaceable.insert(local);
         }
     }
 
     // Second pass: a local can only be fully replaced if all its copies can.
-    ssa.meet_copy_equivalence(&mut replacable);
+    ssa.meet_copy_equivalence(&mut replaceable);
 
-    replacable
+    replaceable
 }
 
 /// Utility to help performing substitution of `*pattern` by `target`.
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 4083038cbb6..cdbc74cdfa8 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -31,7 +31,7 @@ pub(super) fn provide(providers: &mut Providers) {
     providers.mir_shims = make_shim;
 }
 
-// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> acceses
+// Replace Pin<&mut ImplCoroutine> accesses (_1.0) into Pin<&mut ProxyCoroutine> accesses
 struct FixProxyFutureDropVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     replace_to: Local,
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 91e371d697d..131064f9832 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -532,7 +532,7 @@ fn collect_items_rec<'tcx>(
         });
     }
     // Only updating `usage_map` for used items as otherwise we may be inserting the same item
-    // multiple times (if it is first 'mentioned' and then later actuall used), and the usage map
+    // multiple times (if it is first 'mentioned' and then later actually used), and the usage map
     // logic does not like that.
     // This is part of the output of collection and hence only relevant for "used" items.
     // ("Mentioned" items are only considered internally during collection.)
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 49025673bbd..69851511fb1 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -893,7 +893,7 @@ fn mono_item_visibility<'tcx>(
         // * First is weak lang items. These are basically mechanisms for
         //   libcore to forward-reference symbols defined later in crates like
         //   the standard library or `#[panic_handler]` definitions. The
-        //   definition of these weak lang items needs to be referencable by
+        //   definition of these weak lang items needs to be referenceable by
         //   libcore, so we're no longer a candidate for internalization.
         //   Removal of these functions can't be done by LLVM but rather must be
         //   done by the linker as it's a non-local decision.
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 42264f58bcd..61f3f9367f0 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -73,7 +73,7 @@ where
     /// Register additional assumptions for aliases corresponding to `[const]` item bounds.
     ///
     /// Unlike item bounds, they are not simply implied by the well-formedness of the alias.
-    /// Instead, they only hold if the const conditons on the alias also hold. This is why
+    /// Instead, they only hold if the const conditions on the alias also hold. This is why
     /// we also register the const conditions of the alias after matching the goal against
     /// the assumption.
     fn consider_additional_alias_assumptions(
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index cb7c498b94e..5ed316aa6b1 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -88,7 +88,7 @@ where
     /// This takes the `shallow_certainty` which represents whether we're confident
     /// that the final result of the current goal only depends on the nested goals.
     ///
-    /// In case this is `Certainy::Maybe`, there may still be additional nested goals
+    /// In case this is `Certainty::Maybe`, there may still be additional nested goals
     /// or inference constraints required for this candidate to be hold. The candidate
     /// always requires all already added constraints and nested goals.
     #[instrument(level = "trace", skip(self), ret)]
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs
index 26443c54e18..2bb1ac8f742 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs
@@ -42,7 +42,7 @@ where
         // Right now this includes both the impl and the assoc item where bounds,
         // and I don't think the assoc item where-bounds are allowed to be coinductive.
         //
-        // Projecting to the IAT also "steps out the impl contructor", so we would have
+        // Projecting to the IAT also "steps out the impl constructor", so we would have
         // to be very careful when changing the impl where-clauses to be productive.
         self.add_goals(
             GoalSource::Misc,
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 6c9fb63b579..098dc9dbaf0 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -1301,7 +1301,7 @@ where
     D: SolverDelegate<Interner = I>,
     I: Interner,
 {
-    /// FIXME(#57893): For backwards compatability with the old trait solver implementation,
+    /// FIXME(#57893): For backwards compatibility with the old trait solver implementation,
     /// we need to handle overlap between builtin and user-written impls for trait objects.
     ///
     /// This overlap is unsound in general and something which we intend to fix separately.
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index f6e0b08b140..af9f8735549 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -512,6 +512,8 @@ parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
 parse_left_arrow_operator = unexpected token: `<-`
     .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
 
+parse_let_chain_pre_2024 = let chains are only allowed in Rust 2024 or later
+
 parse_lifetime_after_mut = lifetime must precede `mut`
     .suggestion = place the lifetime before `mut`
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 0f0c5434800..7f1b0991f0c 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1779,6 +1779,13 @@ pub(crate) struct AsyncBoundModifierIn2015 {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_let_chain_pre_2024)]
+pub(crate) struct LetChainPre2024 {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_self_argument_pointer)]
 pub(crate) struct SelfArgumentPointer {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 3cedc86dc0d..3d89530f914 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -4117,7 +4117,7 @@ impl MutVisitor for CondChecker<'_> {
                         LetChainsPolicy::AlwaysAllowed => (),
                         LetChainsPolicy::EditionDependent { current_edition } => {
                             if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
-                                self.parser.psess.gated_spans.gate(sym::let_chains, span);
+                                self.parser.dcx().emit_err(errors::LetChainPre2024 { span });
                             }
                         }
                     }
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 8221c709027..0c57a8cc5e1 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -305,8 +305,13 @@ impl<'a> Parser<'a> {
                     let removal_span = kw.span.with_hi(self.token.span.lo());
                     let path = self.parse_path(PathStyle::Type)?;
                     let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
-                    let kind =
-                        self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?;
+                    let kind = self.parse_remaining_bounds_path(
+                        lifetime_defs,
+                        path,
+                        lo,
+                        parse_plus,
+                        ast::Parens::No,
+                    )?;
                     let err = self.dcx().create_err(errors::TransposeDynOrImpl {
                         span: kw.span,
                         kw: kw.name.as_str(),
@@ -333,7 +338,13 @@ impl<'a> Parser<'a> {
                 } else {
                     let path = self.parse_path(PathStyle::Type)?;
                     let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
-                    self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?
+                    self.parse_remaining_bounds_path(
+                        lifetime_defs,
+                        path,
+                        lo,
+                        parse_plus,
+                        ast::Parens::No,
+                    )?
                 }
             }
         } else if self.eat_keyword(exp!(Impl)) {
@@ -413,9 +424,13 @@ impl<'a> Parser<'a> {
             let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
             match ty.kind {
                 // `(TY_BOUND_NOPAREN) + BOUND + ...`.
-                TyKind::Path(None, path) if maybe_bounds => {
-                    self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
-                }
+                TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path(
+                    ThinVec::new(),
+                    path,
+                    lo,
+                    true,
+                    ast::Parens::Yes,
+                ),
                 // For `('a) + …`, we know that `'a` in type position already lead to an error being
                 // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and
                 // other irrelevant consequential errors.
@@ -495,12 +510,14 @@ impl<'a> Parser<'a> {
         path: ast::Path,
         lo: Span,
         parse_plus: bool,
+        parens: ast::Parens,
     ) -> PResult<'a, TyKind> {
         let poly_trait_ref = PolyTraitRef::new(
             generic_params,
             path,
             TraitBoundModifiers::NONE,
             lo.to(self.prev_token.span),
+            parens,
         );
         let bounds = vec![GenericBound::Trait(poly_trait_ref)];
         self.parse_remaining_bounds(bounds, parse_plus)
@@ -826,7 +843,7 @@ impl<'a> Parser<'a> {
             Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? })))
         } else if allow_plus == AllowPlus::Yes && self.check_plus() {
             // `Trait1 + Trait2 + 'a`
-            self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
+            self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No)
         } else {
             // Just a type path.
             Ok(TyKind::Path(None, path))
@@ -892,10 +909,10 @@ impl<'a> Parser<'a> {
     fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
         let lo = self.token.span;
         let leading_token = self.prev_token;
-        let has_parens = self.eat(exp!(OpenParen));
+        let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };
 
         let bound = if self.token.is_lifetime() {
-            self.parse_generic_lt_bound(lo, has_parens)?
+            self.parse_generic_lt_bound(lo, parens)?
         } else if self.eat_keyword(exp!(Use)) {
             // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
             // lifetimes and ident params (including SelfUpper). These are validated later
@@ -904,7 +921,7 @@ impl<'a> Parser<'a> {
             let (args, args_span) = self.parse_precise_capturing_args()?;
             GenericBound::Use(args, use_span.to(args_span))
         } else {
-            self.parse_generic_ty_bound(lo, has_parens, &leading_token)?
+            self.parse_generic_ty_bound(lo, parens, &leading_token)?
         };
 
         Ok(bound)
@@ -914,10 +931,14 @@ impl<'a> Parser<'a> {
     /// ```ebnf
     /// LT_BOUND = LIFETIME
     /// ```
-    fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> {
+    fn parse_generic_lt_bound(
+        &mut self,
+        lo: Span,
+        parens: ast::Parens,
+    ) -> PResult<'a, GenericBound> {
         let lt = self.expect_lifetime();
         let bound = GenericBound::Outlives(lt);
-        if has_parens {
+        if let ast::Parens::Yes = parens {
             // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
             // possibly introducing `GenericBound::Paren(P<GenericBound>)`?
             self.recover_paren_lifetime(lo)?;
@@ -1090,7 +1111,7 @@ impl<'a> Parser<'a> {
     fn parse_generic_ty_bound(
         &mut self,
         lo: Span,
-        has_parens: bool,
+        parens: ast::Parens,
         leading_token: &Token,
     ) -> PResult<'a, GenericBound> {
         let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?;
@@ -1116,7 +1137,7 @@ impl<'a> Parser<'a> {
         // e.g. `T: for<'a> 'a` or `T: [const] 'a`.
         if self.token.is_lifetime() {
             let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);
-            return self.parse_generic_lt_bound(lo, has_parens);
+            return self.parse_generic_lt_bound(lo, parens);
         }
 
         if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? {
@@ -1183,7 +1204,7 @@ impl<'a> Parser<'a> {
             self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
         }
 
-        if has_parens {
+        if let ast::Parens::Yes = parens {
             // Someone has written something like `&dyn (Trait + Other)`. The correct code
             // would be `&(dyn Trait + Other)`
             if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) {
@@ -1203,7 +1224,7 @@ impl<'a> Parser<'a> {
         }
 
         let poly_trait =
-            PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span));
+            PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens);
         Ok(GenericBound::Trait(poly_trait))
     }
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 6c2c571d240..4d64cdeb69a 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -298,6 +298,8 @@ fn emit_malformed_attribute(
             | sym::deprecated
             | sym::optimize
             | sym::cold
+            | sym::target_feature
+            | sym::rustc_allow_const_fn_unstable
             | sym::naked
             | sym::no_mangle
             | sym::must_use
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 9a60c151034..5a94d01e088 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -537,7 +537,7 @@ passes_no_sanitize =
     `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
     .label = not {$accepted_kind}
 
-passes_non_exaustive_with_default_field_values =
+passes_non_exhaustive_with_default_field_values =
     `#[non_exhaustive]` can't be used to annotate items with default field values
     .label = this struct has default field values
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 1b965b9545c..87d46e3e506 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -146,20 +146,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => {
                     self.check_const_continue(hir_id, *attr_span, target)
                 }
-                Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self
-                    .check_allow_internal_unstable(
-                        hir_id,
-                        syms.first().unwrap().1,
-                        span,
-                        target,
-                        attrs,
-                    ),
-                Attribute::Parsed(AttributeKind::AllowConstFnUnstable { .. }) => {
-                    self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
+                Attribute::Parsed(AttributeKind::AllowInternalUnstable(_, first_span)) => {
+                    self.check_allow_internal_unstable(hir_id, *first_span, span, target, attrs)
+                }
+                Attribute::Parsed(AttributeKind::AllowConstFnUnstable(_, first_span)) => {
+                    self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target)
                 }
                 Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
                     self.check_deprecated(hir_id, attr, span, target)
                 }
+                Attribute::Parsed(AttributeKind::TargetFeature(_, attr_span)) => {
+                    self.check_target_feature(hir_id, *attr_span, span, target, attrs)
+                }
                 Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/
                 }
                 Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */
@@ -230,9 +228,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         }
                         [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
                         [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
-                        [sym::target_feature, ..] => {
-                            self.check_target_feature(hir_id, attr, span, target, attrs)
-                        }
                         [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
                         [sym::doc, ..] => self.check_doc_attrs(
                             attr,
@@ -816,7 +811,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     fn check_target_feature(
         &self,
         hir_id: HirId,
-        attr: &Attribute,
+        attr_span: Span,
         span: Span,
         target: Target,
         attrs: &[Attribute],
@@ -834,7 +829,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
 
                     self.dcx().emit_err(errors::LangItemWithTargetFeature {
-                        attr_span: attr.span(),
+                        attr_span,
                         name: lang_item,
                         sig_span: sig.span,
                     });
@@ -846,7 +841,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span(),
+                    attr_span,
                     errors::TargetFeatureOnStatement,
                 );
             }
@@ -855,11 +850,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "target_feature");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "target_feature");
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
-                    attr_span: attr.span(),
+                    attr_span,
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
                 });
@@ -2169,7 +2164,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     fn check_rustc_allow_const_fn_unstable(
         &self,
         hir_id: HirId,
-        attr: &Attribute,
+        attr_span: Span,
         span: Span,
         target: Target,
     ) {
@@ -2181,15 +2176,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => self
-                .inline_attr_str_error_with_macro_def(
-                    hir_id,
-                    attr.span(),
-                    "allow_internal_unstable",
-                ),
+                .inline_attr_str_error_with_macro_def(hir_id, attr_span, "allow_internal_unstable"),
             _ => {
-                self.tcx
-                    .dcx()
-                    .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span(), span });
+                self.tcx.dcx().emit_err(errors::RustcAllowConstFnUnstable { attr_span, span });
             }
         }
     }
@@ -2323,8 +2312,20 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     }
                     return;
                 }
+                AttributeKind::TargetFeature(features, span) if features.len() == 0 => {
+                    self.tcx.emit_node_span_lint(
+                        UNUSED_ATTRIBUTES,
+                        hir_id,
+                        *span,
+                        errors::Unused {
+                            attr_span: *span,
+                            note: errors::UnusedNote::EmptyList { name: sym::target_feature },
+                        },
+                    );
+                    return;
+                }
                 _ => {}
-            }
+            };
         }
 
         // Warn on useless empty attributes.
@@ -2336,7 +2337,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             sym::deny,
             sym::forbid,
             sym::feature,
-            sym::target_feature,
         ]) && attr.meta_item_list().is_some_and(|list| list.is_empty())
         {
             errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index ce43b2c281d..cdfd1a2b07e 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -1199,7 +1199,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
         let def_kind = tcx.def_kind(item.owner_id);
 
         let mut dead_codes = Vec::new();
-        // Only diagnose unused assoc items in inherient impl and used trait,
+        // Only diagnose unused assoc items in inherent impl and used trait,
         // for unused assoc items in impls of trait,
         // we have diagnosed them in the trait if they are unused,
         // for unused assoc items in unused trait,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index d4988277073..3ede3c889c8 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -157,7 +157,7 @@ pub(crate) struct NonExhaustiveWrongLocation {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_non_exaustive_with_default_field_values)]
+#[diag(passes_non_exhaustive_with_default_field_values)]
 pub(crate) struct NonExhaustiveWithDefaultFieldValues {
     #[primary_span]
     pub attr_span: Span,
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 53638f2a57d..c348cd508f9 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -70,7 +70,7 @@
 //! # Constructors and fields
 //!
 //! In the value `Pair(Some(0), true)`, `Pair` is called the constructor of the value, and `Some(0)`
-//! and `true` are its fields. Every matcheable value can be decomposed in this way. Examples of
+//! and `true` are its fields. Every matchable value can be decomposed in this way. Examples of
 //! constructors are: `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor
 //! for a struct `Foo`), and `2` (the constructor for the number `2`).
 //!
@@ -102,7 +102,7 @@
 //! [`Constructor::is_covered_by`].
 //!
 //! Note 1: variable bindings (like the `x` in `Some(x)`) match anything, so we treat them as wildcards.
-//! Note 2: this only applies to matcheable values. For example a value of type `Rc<u64>` can't be
+//! Note 2: this only applies to matchable values. For example a value of type `Rc<u64>` can't be
 //! deconstructed that way.
 //!
 //!
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 7d80e54bf87..7be75ea88ac 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -259,4 +259,5 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
     for alloc in super::ALLOC_SELF_PROFILE_QUERY_STRINGS.iter() {
         alloc(tcx, &mut string_cache)
     }
+    tcx.sess.prof.store_query_cache_hits();
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index d4217e0aa54..04fc32a9b50 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1342,7 +1342,7 @@ impl DepNodeColorMap {
 
     /// This tries to atomically mark a node green and assign `index` as the new
     /// index. This returns `Ok` if `index` gets assigned, otherwise it returns
-    /// the alreadly allocated index in `Err`.
+    /// the already allocated index in `Err`.
     #[inline]
     pub(super) fn try_mark_green(
         &self,
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 58942474e32..aa818cc9c46 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -432,6 +432,7 @@ resolve_undeclared_label =
 
 resolve_underscore_lifetime_is_reserved = `'_` cannot be used here
     .label = `'_` is a reserved lifetime name
+    .help = use another lifetime specifier
 
 resolve_unexpected_res_change_ty_to_const_param_sugg =
     you might have meant to write a const parameter here
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 6d3752c0c83..b34bcb38f84 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -878,12 +878,12 @@ pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments {
 
 #[derive(Diagnostic)]
 #[diag(resolve_elided_anonymous_lifetime_report_error, code = E0637)]
-pub(crate) struct ElidedAnonymousLivetimeReportError {
+pub(crate) struct ElidedAnonymousLifetimeReportError {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
     #[subdiagnostic]
-    pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>,
+    pub(crate) suggestion: Option<ElidedAnonymousLifetimeReportErrorSuggestion>,
 }
 
 #[derive(Diagnostic)]
@@ -897,7 +897,7 @@ pub(crate) struct LendingIteratorReportError {
 
 #[derive(Diagnostic)]
 #[diag(resolve_anonymous_lifetime_non_gat_report_error)]
-pub(crate) struct AnonymousLivetimeNonGatReportError {
+pub(crate) struct AnonymousLifetimeNonGatReportError {
     #[primary_span]
     #[label]
     pub(crate) lifetime: Span,
@@ -908,7 +908,7 @@ pub(crate) struct AnonymousLivetimeNonGatReportError {
     resolve_elided_anonymous_lifetime_report_error_suggestion,
     applicability = "machine-applicable"
 )]
-pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion {
+pub(crate) struct ElidedAnonymousLifetimeReportErrorSuggestion {
     #[suggestion_part(code = "for<'a> ")]
     pub(crate) lo: Span,
     #[suggestion_part(code = "'a ")]
@@ -917,7 +917,7 @@ pub(crate) struct ElidedAnonymousLivetimeReportErrorSuggestion {
 
 #[derive(Diagnostic)]
 #[diag(resolve_explicit_anonymous_lifetime_report_error, code = E0637)]
-pub(crate) struct ExplicitAnonymousLivetimeReportError {
+pub(crate) struct ExplicitAnonymousLifetimeReportError {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
@@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
 
 #[derive(Diagnostic)]
 #[diag(resolve_underscore_lifetime_is_reserved, code = E0637)]
+#[help]
 pub(crate) struct UnderscoreLifetimeIsReserved {
     #[primary_span]
     #[label]
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ac7bdda4195..c2bea4e0fdc 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1892,7 +1892,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                                 ..
                             } = rib.kind
                             {
-                                Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion {
+                                Some(errors::ElidedAnonymousLifetimeReportErrorSuggestion {
                                     lo: span.shrink_to_lo(),
                                     hi: lifetime.ident.span.shrink_to_hi(),
                                 })
@@ -1918,18 +1918,18 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                                     ty: ty.span,
                                 });
                             } else {
-                                self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError {
+                                self.r.dcx().emit_err(errors::AnonymousLifetimeNonGatReportError {
                                     lifetime: lifetime.ident.span,
                                 });
                             }
                         } else {
-                            self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError {
+                            self.r.dcx().emit_err(errors::ElidedAnonymousLifetimeReportError {
                                 span: lifetime.ident.span,
                                 suggestion,
                             });
                         }
                     } else {
-                        self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError {
+                        self.r.dcx().emit_err(errors::ExplicitAnonymousLifetimeReportError {
                             span: lifetime.ident.span,
                         });
                     };
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index e7b8c988cd4..6230b8cfbec 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -3832,6 +3832,7 @@ fn mk_where_bound_predicate(
                 ref_id: DUMMY_NODE_ID,
             },
             span: DUMMY_SP,
+            parens: ast::Parens::No,
         })],
     };
 
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 3fe5db8ca54..f61cd1f0adf 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -627,7 +627,7 @@ pub fn source_span_for_markdown_range_inner(
             let fragment = &fragments[i];
             let sp = fragment.span;
             // we need to calculate the span start,
-            // then use that in our calulations for the span end
+            // then use that in our calculations for the span end
             let lo = sp.lo() + BytePos(match_start as u32);
             return Some((
                 sp.with_lo(lo).with_hi(lo + BytePos((md_range.end - md_range.start) as u32)),
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 6ea70600626..1cb09e8a1ee 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -21,7 +21,7 @@ use thin_vec::ThinVec;
 /// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout
 const STR_SENTINEL: u8 = 0xC1;
 
-/// For byte strings there are no bytes that canot occur. Just use this value
+/// For byte strings there are no bytes that cannot occur. Just use this value
 /// as a best-effort sentinel. There is no validation skipped so the potential
 /// for badness is lower than in the `STR_SENTINEL` case.
 const BYTE_STR_SENTINEL: u8 = 0xC2;
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 73bb0471c22..74e766a1e95 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -190,7 +190,7 @@ pub struct CoverageOptions {
     /// to keep supporting this flag, remove it.
     pub no_mir_spans: bool,
 
-    /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codgen,
+    /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codegen,
     /// discard all coverage spans as though they were invalid. Needed by
     /// regression tests for #133606, because we don't have an easy way to
     /// reproduce it from actual source code.
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index bad2581ae31..8386fe8dab0 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1545,7 +1545,7 @@ impl RemapFileNameExt for rustc_span::FileName {
             "one and only one scope should be passed to for_scope"
         );
         if sess.opts.unstable_opts.remap_path_scope.contains(scope) {
-            self.prefer_remapped_unconditionaly()
+            self.prefer_remapped_unconditionally()
         } else {
             self.prefer_local()
         }
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index baa4c0681e8..3fa83cfc6a0 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -130,7 +130,11 @@ impl<'tcx> SmirCtxt<'tcx> {
 
     pub fn all_trait_decls(&self) -> stable_mir::TraitDecls {
         let mut tables = self.0.borrow_mut();
-        tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect()
+        tables
+            .tcx
+            .all_traits_including_private()
+            .map(|trait_def_id| tables.trait_def(trait_def_id))
+            .collect()
     }
 
     pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 4ea2bb04c5d..398738d1c38 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -1600,7 +1600,7 @@ pub struct VariantIdx(usize);
 index_impl!(VariantIdx);
 
 crate_def! {
-    /// Hold infomation about an Opaque definition, particularly useful in `RPITIT`.
+    /// Hold information about an Opaque definition, particularly useful in `RPITIT`.
     #[derive(Serialize)]
     pub OpaqueDef;
 }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index c18ff285c4e..9b0e009b2cd 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -418,7 +418,7 @@ impl FileName {
         }
     }
 
-    pub fn prefer_remapped_unconditionaly(&self) -> FileNameDisplay<'_> {
+    pub fn prefer_remapped_unconditionally(&self) -> FileNameDisplay<'_> {
         FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
     }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 34869a38bb4..d6537d49be7 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1775,7 +1775,6 @@ symbols! {
         resume,
         return_position_impl_trait_in_trait,
         return_type_notation,
-        rhs,
         riscv_target_feature,
         rlib,
         ropi,
@@ -2398,7 +2397,7 @@ pub const STDLIB_STABLE_CRATES: &[Symbol] = &[sym::std, sym::core, sym::alloc, s
 #[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)]
 pub struct Ident {
     // `name` should never be the empty symbol. If you are considering that,
-    // you are probably conflating "empty identifer with "no identifier" and
+    // you are probably conflating "empty identifier with "no identifier" and
     // you should use `Option<Ident>` instead.
     pub name: Symbol,
     pub span: Span,
diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs
index 1ba792c5acc..d2ae404b23b 100644
--- a/compiler/rustc_target/src/callconv/s390x.rs
+++ b/compiler/rustc_target/src/callconv/s390x.rs
@@ -46,7 +46,7 @@ where
         }
 
         if arg.layout.is_single_vector_element(cx, size) {
-            // pass non-transparant wrappers around a vector as `PassMode::Cast`
+            // pass non-transparent wrappers around a vector as `PassMode::Cast`
             arg.cast_to(Reg { kind: RegKind::Vector, size });
             return;
         }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
index 66733d5d4b8..b01ca989282 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
index ecf68ddff8c..bc7e445f3f8 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv1".into();
     base.llvm_abiname = "elfv1".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index e205aef8285..4dc76f0936c 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -12,6 +12,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
index bcb328020ee..9dc44aa05cc 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
index 37c888ba514..10072f8092d 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv1".into();
     base.llvm_abiname = "elfv1".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
index 3096c4d14ad..a7f4e0eabb0 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
index 9e406af53b5..af5704b51ba 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
index f145c5b8c14..26ee6a68c6a 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.abi = "elfv2".into();
     base.llvm_abiname = "elfv2".into();
 
     Target {
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index 1071105522d..62f1d908601 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2024"
 itertools = "0.12"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_attr_data_structures = {path = "../rustc_attr_data_structures"}
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index aea42df4dfd..bff5e9128cb 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -1,3 +1,4 @@
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{Diag, MultiSpan, pluralize};
 use rustc_hir as hir;
@@ -8,7 +9,7 @@ use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::print::{FmtPrinter, Printer};
 use rustc_middle::ty::{self, Ty, suggest_constraining_type_param};
 use rustc_span::def_id::DefId;
-use rustc_span::{BytePos, Span, Symbol, sym};
+use rustc_span::{BytePos, Span, Symbol};
 use tracing::debug;
 
 use crate::error_reporting::TypeErrCtxt;
@@ -535,8 +536,7 @@ impl<T> Trait<T> for X {
                 }
             }
             TypeError::TargetFeatureCast(def_id) => {
-                let target_spans =
-                    tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span());
+                let target_spans = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature(.., span) => *span);
                 diag.note(
                     "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
                 );
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index c72eff1d231..28d572b303a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1855,7 +1855,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let trait_def_id = trait_pred.def_id();
         let trait_name = self.tcx.item_name(trait_def_id);
         let crate_name = self.tcx.crate_name(trait_def_id.krate);
-        if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| {
+        if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| {
             trait_name == self.tcx.item_name(trait_def_id)
                 && trait_def_id.krate != def_id.krate
                 && crate_name == self.tcx.crate_name(def_id.krate)
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 2bbf90ed3ed..362052e9fdb 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -4432,7 +4432,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         candidate_impls: &[ImplCandidate<'tcx>],
         span: Span,
     ) {
-        // We can only suggest the slice coersion for function and binary operation arguments,
+        // We can only suggest the slice coercion for function and binary operation arguments,
         // since the suggestion would make no sense in turbofish or call
         let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) =
             obligation.cause.code()
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 7bf49056e29..90cdf75265d 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -643,7 +643,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
                 // Do not suggest constraining the `&self` param, but rather the return type.
                 // If that is wrong (because it is not sufficient), a follow up error will tell the
                 // user to fix it. This way we lower the chances of *over* constraining, but still
-                // get the cake of "correctly" contrained in two steps.
+                // get the cake of "correctly" constrained in two steps.
                 visitor.visit_ty_unambig(self.ty_sup);
             }
             visitor.visit_ty_unambig(self.ty_sub);
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 8d049fedf23..9a4f3887bbb 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -31,7 +31,7 @@ use crate::traits::{
 ///
 /// Currently that is `Self` in supertraits. This is needed
 /// because `dyn_compatibility_violations` can't be used during
-/// type collection, as type collection is needed for `dyn_compatiblity_violations` itself.
+/// type collection, as type collection is needed for `dyn_compatibility_violations` itself.
 #[instrument(level = "debug", skip(tcx), ret)]
 pub fn hir_ty_lowering_dyn_compatibility_violations(
     tcx: TyCtxt<'_>,
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index fc95e42d67f..176d308de91 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -44,6 +44,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
         Err(EvaluationFailure::NoSolution) => {}
     }
 
+    match evaluate_host_effect_from_conditionally_const_item_bounds(selcx, obligation) {
+        Ok(result) => return Ok(result),
+        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
+        Err(EvaluationFailure::NoSolution) => {}
+    }
+
     match evaluate_host_effect_from_item_bounds(selcx, obligation) {
         Ok(result) => return Ok(result),
         Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
@@ -56,7 +62,7 @@ pub fn evaluate_host_effect_obligation<'tcx>(
         Err(EvaluationFailure::NoSolution) => {}
     }
 
-    match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
+    match evaluate_host_effect_from_selection_candidate(selcx, obligation) {
         Ok(result) => return Ok(result),
         Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
         Err(EvaluationFailure::NoSolution) => {}
@@ -153,7 +159,9 @@ fn evaluate_host_effect_from_bounds<'tcx>(
     }
 }
 
-fn evaluate_host_effect_from_item_bounds<'tcx>(
+/// Assembles constness bounds from `~const` item bounds on alias types, which only
+/// hold if the `~const` where bounds also hold and the parent trait is `~const`.
+fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
@@ -232,6 +240,63 @@ fn evaluate_host_effect_from_item_bounds<'tcx>(
     }
 }
 
+/// Assembles constness bounds "normal" item bounds on aliases, which may include
+/// unconditionally `const` bounds that are *not* conditional and thus always hold.
+fn evaluate_host_effect_from_item_bounds<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+    let infcx = selcx.infcx;
+    let tcx = infcx.tcx;
+    let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
+    let mut candidate = None;
+
+    let mut consider_ty = obligation.predicate.self_ty();
+    while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
+        for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) {
+            let bound_clause = clause.kind();
+            let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
+                continue;
+            };
+            let data = bound_clause.rebind(data);
+            if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
+                continue;
+            }
+
+            if !drcx.args_may_unify(
+                obligation.predicate.trait_ref.args,
+                data.skip_binder().trait_ref.args,
+            ) {
+                continue;
+            }
+
+            let is_match =
+                infcx.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok());
+
+            if is_match {
+                if candidate.is_some() {
+                    return Err(EvaluationFailure::Ambiguous);
+                } else {
+                    candidate = Some(data);
+                }
+            }
+        }
+
+        if kind != ty::Projection {
+            break;
+        }
+
+        consider_ty = alias_ty.self_ty();
+    }
+
+    if let Some(data) = candidate {
+        Ok(match_candidate(selcx, obligation, data, true, |_, _| {})
+            .expect("candidate matched before, so it should match again"))
+    } else {
+        Err(EvaluationFailure::NoSolution)
+    }
+}
+
 fn evaluate_host_effect_from_builtin_impls<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
@@ -333,7 +398,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
         .collect())
 }
 
-fn evaluate_host_effect_from_selection_candiate<'tcx>(
+fn evaluate_host_effect_from_selection_candidate<'tcx>(
     selcx: &mut SelectionContext<'_, 'tcx>,
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 43806d3977b..91c41544f78 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -481,7 +481,7 @@ pub enum EvaluateConstErr {
     /// some unevaluated constant with either generic parameters or inference variables in its
     /// generic arguments.
     HasGenericsOrInfers,
-    /// The type this constant evalauted to is not valid for use in const generics. This should
+    /// The type this constant evaluated to is not valid for use in const generics. This should
     /// always result in an error when checking the constant is correctly typed for the parameter
     /// it is an argument to, so a bug is delayed when encountering this.
     InvalidConstParamTy(ErrorGuaranteed),
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 18971c47831..22eeb285b37 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -21,19 +21,9 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
 
         if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) =
             key.value.predicate.kind().skip_binder()
+            && term.is_trivially_wf(tcx)
         {
-            match term.as_type()?.kind() {
-                ty::Param(_)
-                | ty::Bool
-                | ty::Char
-                | ty::Int(_)
-                | ty::Float(_)
-                | ty::Str
-                | ty::Uint(_) => {
-                    return Some(());
-                }
-                _ => {}
-            }
+            return Some(());
         }
 
         None
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 3eca77b43a8..3a369f13e79 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -904,7 +904,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let goal_kind =
             self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
 
-        // If we have not yet determiend the `ClosureKind` of the closure or coroutine-closure,
+        // If we have not yet determined the `ClosureKind` of the closure or coroutine-closure,
         // then additionally register an `AsyncFnKindHelper` goal which will fail if the kind
         // is constrained to an insufficient type later on.
         if let Some(closure_kind) = self.infcx.shallow_resolve(kind_ty).to_opt_closure_kind() {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index a05bae53566..141454bfe37 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -368,16 +368,17 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
     // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
     // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
     // canonicalize and all that for such cases.
-    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
+    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
         predicate.kind().skip_binder()
+        && trait_pred.polarity == ty::PredicatePolarity::Positive
     {
-        let sizedness = match tcx.as_lang_item(trait_ref.def_id()) {
+        let sizedness = match tcx.as_lang_item(trait_pred.def_id()) {
             Some(LangItem::Sized) => SizedTraitKind::Sized,
             Some(LangItem::MetaSized) => SizedTraitKind::MetaSized,
             _ => return false,
         };
 
-        if trait_ref.self_ty().has_trivial_sizedness(tcx, sizedness) {
+        if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) {
             debug!("fast path -- trivial sizedness");
             return true;
         }
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 9d144010561..7dd3c59edd0 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -6,11 +6,11 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::traits::CodegenObligationError;
-use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, Upcast};
+use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{
     ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
-    SelectionError, sizedness_fast_path,
+    SelectionError,
 };
 use tracing::debug;
 
@@ -34,13 +34,6 @@ pub(crate) fn codegen_select_candidate<'tcx>(
     let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env);
     let mut selcx = SelectionContext::new(&infcx);
 
-    if sizedness_fast_path(tcx, trait_ref.upcast(tcx)) {
-        return Ok(&*tcx.arena.alloc(ImplSource::Builtin(
-            ty::solve::BuiltinImplSource::Trivial,
-            Default::default(),
-        )));
-    }
-
     let obligation_cause = ObligationCause::dummy();
     let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref);
 
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index f14a45aa1e3..a65f9b347dc 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -1,9 +1,8 @@
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatorState};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, AmbigArg};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -14,7 +13,6 @@ pub(crate) fn provide(providers: &mut Providers) {
         associated_item_def_ids,
         associated_items,
         associated_types_for_impl_traits_in_associated_fn,
-        associated_type_for_impl_trait_in_trait,
         impl_item_implementor_ids,
         ..*providers
     };
@@ -160,20 +158,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
         container: ty::AssocItemContainer::Impl,
     }
 }
-struct RPITVisitor {
-    rpits: FxIndexSet<LocalDefId>,
+struct RPITVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    synthetics: Vec<LocalDefId>,
+    data: DefPathData,
+    disambiguator: DisambiguatorState,
 }
 
-impl<'tcx> Visitor<'tcx> for RPITVisitor {
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
-        if let hir::TyKind::OpaqueDef(opaq) = ty.kind
-            && self.rpits.insert(opaq.def_id)
-        {
-            for bound in opaq.bounds {
-                intravisit::walk_param_bound(self, bound);
-            }
-        }
-        intravisit::walk_ty(self, ty)
+impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
+    fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
+        self.synthetics.push(associated_type_for_impl_trait_in_trait(
+            self.tcx,
+            opaque.def_id,
+            self.data,
+            &mut self.disambiguator,
+        ));
+        intravisit::walk_opaque_ty(self, opaque)
     }
 }
 
@@ -194,14 +194,18 @@ fn associated_types_for_impl_traits_in_associated_fn(
 
     match tcx.def_kind(parent_def_id) {
         DefKind::Trait => {
-            let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
-
             if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
+                let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
+                let mut visitor = RPITVisitor {
+                    tcx,
+                    synthetics: vec![],
+                    data,
+                    disambiguator: DisambiguatorState::with(parent_def_id, data, 0),
+                };
                 visitor.visit_fn_ret_ty(output);
-
-                tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
-                    tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
-                }))
+                tcx.arena.alloc_from_iter(
+                    visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()),
+                )
             } else {
                 &[]
             }
@@ -211,7 +215,6 @@ fn associated_types_for_impl_traits_in_associated_fn(
             let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else {
                 return &[];
             };
-
             tcx.arena.alloc_from_iter(
                 tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
                     move |&trait_assoc_def_id| {
@@ -236,6 +239,8 @@ fn associated_types_for_impl_traits_in_associated_fn(
 fn associated_type_for_impl_trait_in_trait(
     tcx: TyCtxt<'_>,
     opaque_ty_def_id: LocalDefId,
+    data: DefPathData,
+    disambiguator: &mut DisambiguatorState,
 ) -> LocalDefId {
     let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
     | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
@@ -246,22 +251,15 @@ fn associated_type_for_impl_trait_in_trait(
     let trait_def_id = tcx.local_parent(fn_def_id);
     assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
 
-    // Collect all opaque types in return position for the method and use
-    // the index as the disambiguator to make an unique def path.
-    let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
-    visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap());
-    let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap();
-
     let span = tcx.def_span(opaque_ty_def_id);
     // Also use the method name to create an unique def path.
-    let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
     let trait_assoc_ty = tcx.at(span).create_def(
         trait_def_id,
         // No name because this is an anonymous associated type.
         None,
         DefKind::AssocTy,
         Some(data),
-        &mut DisambiguatorState::with(trait_def_id, data, disambiguator),
+        disambiguator,
     );
 
     let local_def_id = trait_assoc_ty.def_id();
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index 3b4482146d4..3b313edea6f 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -179,7 +179,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
         }
     }
 
-    /// Checks the `#[define_opaque]` attributes on items and collectes opaques to define
+    /// Checks the `#[define_opaque]` attributes on items and collects opaques to define
     /// from the referenced types.
     #[instrument(level = "trace", skip(self))]
     fn collect_taits_from_defines_attr(&mut self) {
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 8ba9e7105d6..6c77a90250a 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -13,7 +13,7 @@ use crate::{self as ty, Interner};
 /// slightly different typing rules depending on the current context. See the
 /// doc comment for each variant for how and why they are used.
 ///
-/// In most cases you can get the correct typing mode automically via:
+/// In most cases you can get the correct typing mode automatically via:
 /// - `mir::Body::typing_mode`
 /// - `rustc_lint::LateContext::typing_mode`
 ///
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
index 8941360d2d0..7433c215e6f 100644
--- a/compiler/rustc_type_ir/src/search_graph/mod.rs
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -390,8 +390,8 @@ impl PathsToNested {
 ///
 /// They are used when checking whether reevaluating a global cache
 /// would encounter a cycle or use a provisional cache entry given the
-/// currentl search graph state. We need to disable the global cache
-/// in this case as it could otherwise result in behaviorial differences.
+/// current search graph state. We need to disable the global cache
+/// in this case as it could otherwise result in behavioral differences.
 /// Cycles can impact behavior. The cycle ABA may have different final
 /// results from a the cycle BAB depending on the cycle root.
 ///
@@ -513,7 +513,7 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
 ///
 /// `nested_goals` are only used when checking whether global cache entries
 /// are applicable. This only cares about whether a goal is actually accessed.
-/// Given that the usage of the provisional cache is fully determinstic, we
+/// Given that the usage of the provisional cache is fully deterministic, we
 /// don't need to track the nested goals used while computing a provisional
 /// cache entry.
 enum UpdateParentGoalCtxt<'a, X: Cx> {
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 4536f555443..4e3f76de49e 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1098,115 +1098,6 @@ impl<T: ?Sized> Box<T> {
     pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
         unsafe { Self::from_raw(ptr.as_ptr()) }
     }
-}
-
-impl<T: ?Sized, A: Allocator> Box<T, A> {
-    /// Constructs a box from a raw pointer in the given allocator.
-    ///
-    /// After calling this function, the raw pointer is owned by the
-    /// resulting `Box`. Specifically, the `Box` destructor will call
-    /// the destructor of `T` and free the allocated memory. For this
-    /// to be safe, the memory must have been allocated in accordance
-    /// with the [memory layout] used by `Box` .
-    ///
-    /// # Safety
-    ///
-    /// This function is unsafe because improper use may lead to
-    /// memory problems. For example, a double-free may occur if the
-    /// function is called twice on the same raw pointer.
-    ///
-    /// The raw pointer must point to a block of memory allocated by `alloc`.
-    ///
-    /// # Examples
-    ///
-    /// Recreate a `Box` which was previously converted to a raw pointer
-    /// using [`Box::into_raw_with_allocator`]:
-    /// ```
-    /// #![feature(allocator_api)]
-    ///
-    /// use std::alloc::System;
-    ///
-    /// let x = Box::new_in(5, System);
-    /// let (ptr, alloc) = Box::into_raw_with_allocator(x);
-    /// let x = unsafe { Box::from_raw_in(ptr, alloc) };
-    /// ```
-    /// Manually create a `Box` from scratch by using the system allocator:
-    /// ```
-    /// #![feature(allocator_api, slice_ptr_get)]
-    ///
-    /// use std::alloc::{Allocator, Layout, System};
-    ///
-    /// unsafe {
-    ///     let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32;
-    ///     // In general .write is required to avoid attempting to destruct
-    ///     // the (uninitialized) previous contents of `ptr`, though for this
-    ///     // simple example `*ptr = 5` would have worked as well.
-    ///     ptr.write(5);
-    ///     let x = Box::from_raw_in(ptr, System);
-    /// }
-    /// # Ok::<(), std::alloc::AllocError>(())
-    /// ```
-    ///
-    /// [memory layout]: self#memory-layout
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    #[inline]
-    pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
-        Box(unsafe { Unique::new_unchecked(raw) }, alloc)
-    }
-
-    /// Constructs a box from a `NonNull` pointer in the given allocator.
-    ///
-    /// After calling this function, the `NonNull` pointer is owned by
-    /// the resulting `Box`. Specifically, the `Box` destructor will call
-    /// the destructor of `T` and free the allocated memory. For this
-    /// to be safe, the memory must have been allocated in accordance
-    /// with the [memory layout] used by `Box` .
-    ///
-    /// # Safety
-    ///
-    /// This function is unsafe because improper use may lead to
-    /// memory problems. For example, a double-free may occur if the
-    /// function is called twice on the same raw pointer.
-    ///
-    /// The non-null pointer must point to a block of memory allocated by `alloc`.
-    ///
-    /// # Examples
-    ///
-    /// Recreate a `Box` which was previously converted to a `NonNull` pointer
-    /// using [`Box::into_non_null_with_allocator`]:
-    /// ```
-    /// #![feature(allocator_api, box_vec_non_null)]
-    ///
-    /// use std::alloc::System;
-    ///
-    /// let x = Box::new_in(5, System);
-    /// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
-    /// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
-    /// ```
-    /// Manually create a `Box` from scratch by using the system allocator:
-    /// ```
-    /// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)]
-    ///
-    /// use std::alloc::{Allocator, Layout, System};
-    ///
-    /// unsafe {
-    ///     let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>();
-    ///     // In general .write is required to avoid attempting to destruct
-    ///     // the (uninitialized) previous contents of `non_null`.
-    ///     non_null.write(5);
-    ///     let x = Box::from_non_null_in(non_null, System);
-    /// }
-    /// # Ok::<(), std::alloc::AllocError>(())
-    /// ```
-    ///
-    /// [memory layout]: self#memory-layout
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
-    #[inline]
-    pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
-        // SAFETY: guaranteed by the caller.
-        unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
-    }
 
     /// Consumes the `Box`, returning a wrapped raw pointer.
     ///
@@ -1259,8 +1150,11 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     #[stable(feature = "box_raw", since = "1.4.0")]
     #[inline]
     pub fn into_raw(b: Self) -> *mut T {
-        // Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here.
-        unsafe { &raw mut *&mut *Self::into_raw_with_allocator(b).0 }
+        // Avoid `into_raw_with_allocator` as that interacts poorly with Miri's Stacked Borrows.
+        let mut b = mem::ManuallyDrop::new(b);
+        // We go through the built-in deref for `Box`, which is crucial for Miri to recognize this
+        // operation for it's alias tracking.
+        &raw mut **b
     }
 
     /// Consumes the `Box`, returning a wrapped `NonNull` pointer.
@@ -1322,6 +1216,115 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
         // SAFETY: `Box` is guaranteed to be non-null.
         unsafe { NonNull::new_unchecked(Self::into_raw(b)) }
     }
+}
+
+impl<T: ?Sized, A: Allocator> Box<T, A> {
+    /// Constructs a box from a raw pointer in the given allocator.
+    ///
+    /// After calling this function, the raw pointer is owned by the
+    /// resulting `Box`. Specifically, the `Box` destructor will call
+    /// the destructor of `T` and free the allocated memory. For this
+    /// to be safe, the memory must have been allocated in accordance
+    /// with the [memory layout] used by `Box` .
+    ///
+    /// # Safety
+    ///
+    /// This function is unsafe because improper use may lead to
+    /// memory problems. For example, a double-free may occur if the
+    /// function is called twice on the same raw pointer.
+    ///
+    /// The raw pointer must point to a block of memory allocated by `alloc`.
+    ///
+    /// # Examples
+    ///
+    /// Recreate a `Box` which was previously converted to a raw pointer
+    /// using [`Box::into_raw_with_allocator`]:
+    /// ```
+    /// #![feature(allocator_api)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// let x = Box::new_in(5, System);
+    /// let (ptr, alloc) = Box::into_raw_with_allocator(x);
+    /// let x = unsafe { Box::from_raw_in(ptr, alloc) };
+    /// ```
+    /// Manually create a `Box` from scratch by using the system allocator:
+    /// ```
+    /// #![feature(allocator_api, slice_ptr_get)]
+    ///
+    /// use std::alloc::{Allocator, Layout, System};
+    ///
+    /// unsafe {
+    ///     let ptr = System.allocate(Layout::new::<i32>())?.as_mut_ptr() as *mut i32;
+    ///     // In general .write is required to avoid attempting to destruct
+    ///     // the (uninitialized) previous contents of `ptr`, though for this
+    ///     // simple example `*ptr = 5` would have worked as well.
+    ///     ptr.write(5);
+    ///     let x = Box::from_raw_in(ptr, System);
+    /// }
+    /// # Ok::<(), std::alloc::AllocError>(())
+    /// ```
+    ///
+    /// [memory layout]: self#memory-layout
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[inline]
+    pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
+        Box(unsafe { Unique::new_unchecked(raw) }, alloc)
+    }
+
+    /// Constructs a box from a `NonNull` pointer in the given allocator.
+    ///
+    /// After calling this function, the `NonNull` pointer is owned by
+    /// the resulting `Box`. Specifically, the `Box` destructor will call
+    /// the destructor of `T` and free the allocated memory. For this
+    /// to be safe, the memory must have been allocated in accordance
+    /// with the [memory layout] used by `Box` .
+    ///
+    /// # Safety
+    ///
+    /// This function is unsafe because improper use may lead to
+    /// memory problems. For example, a double-free may occur if the
+    /// function is called twice on the same raw pointer.
+    ///
+    /// The non-null pointer must point to a block of memory allocated by `alloc`.
+    ///
+    /// # Examples
+    ///
+    /// Recreate a `Box` which was previously converted to a `NonNull` pointer
+    /// using [`Box::into_non_null_with_allocator`]:
+    /// ```
+    /// #![feature(allocator_api, box_vec_non_null)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// let x = Box::new_in(5, System);
+    /// let (non_null, alloc) = Box::into_non_null_with_allocator(x);
+    /// let x = unsafe { Box::from_non_null_in(non_null, alloc) };
+    /// ```
+    /// Manually create a `Box` from scratch by using the system allocator:
+    /// ```
+    /// #![feature(allocator_api, box_vec_non_null, slice_ptr_get)]
+    ///
+    /// use std::alloc::{Allocator, Layout, System};
+    ///
+    /// unsafe {
+    ///     let non_null = System.allocate(Layout::new::<i32>())?.cast::<i32>();
+    ///     // In general .write is required to avoid attempting to destruct
+    ///     // the (uninitialized) previous contents of `non_null`.
+    ///     non_null.write(5);
+    ///     let x = Box::from_non_null_in(non_null, System);
+    /// }
+    /// # Ok::<(), std::alloc::AllocError>(())
+    /// ```
+    ///
+    /// [memory layout]: self#memory-layout
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
+    #[inline]
+    pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
+        // SAFETY: guaranteed by the caller.
+        unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
+    }
 
     /// Consumes the `Box`, returning a wrapped raw pointer and the allocator.
     ///
@@ -1602,7 +1605,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     where
         A: 'a,
     {
-        unsafe { &mut *Box::into_raw(b) }
+        let (ptr, alloc) = Box::into_raw_with_allocator(b);
+        mem::forget(alloc);
+        unsafe { &mut *ptr }
     }
 
     /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 010d17f7476..5018ff4ad71 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1322,6 +1322,30 @@ impl<T: ?Sized> Rc<T> {
         unsafe { Self::from_raw_in(ptr, Global) }
     }
 
+    /// Consumes the `Rc`, returning the wrapped pointer.
+    ///
+    /// To avoid a memory leak the pointer must be converted back to an `Rc` using
+    /// [`Rc::from_raw`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::rc::Rc;
+    ///
+    /// let x = Rc::new("hello".to_owned());
+    /// let x_ptr = Rc::into_raw(x);
+    /// assert_eq!(unsafe { &*x_ptr }, "hello");
+    /// # // Prevent leaks for Miri.
+    /// # drop(unsafe { Rc::from_raw(x_ptr) });
+    /// ```
+    #[must_use = "losing the pointer will leak memory"]
+    #[stable(feature = "rc_raw", since = "1.17.0")]
+    #[rustc_never_returns_null_ptr]
+    pub fn into_raw(this: Self) -> *const T {
+        let this = ManuallyDrop::new(this);
+        Self::as_ptr(&*this)
+    }
+
     /// Increments the strong reference count on the `Rc<T>` associated with the
     /// provided pointer by one.
     ///
@@ -1408,30 +1432,6 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
         &this.alloc
     }
 
-    /// Consumes the `Rc`, returning the wrapped pointer.
-    ///
-    /// To avoid a memory leak the pointer must be converted back to an `Rc` using
-    /// [`Rc::from_raw`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::rc::Rc;
-    ///
-    /// let x = Rc::new("hello".to_owned());
-    /// let x_ptr = Rc::into_raw(x);
-    /// assert_eq!(unsafe { &*x_ptr }, "hello");
-    /// # // Prevent leaks for Miri.
-    /// # drop(unsafe { Rc::from_raw(x_ptr) });
-    /// ```
-    #[must_use = "losing the pointer will leak memory"]
-    #[stable(feature = "rc_raw", since = "1.17.0")]
-    #[rustc_never_returns_null_ptr]
-    pub fn into_raw(this: Self) -> *const T {
-        let this = ManuallyDrop::new(this);
-        Self::as_ptr(&*this)
-    }
-
     /// Consumes the `Rc`, returning the wrapped pointer and allocator.
     ///
     /// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -1525,7 +1525,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// use std::alloc::System;
     ///
     /// let x = Rc::new_in("hello".to_owned(), System);
-    /// let x_ptr = Rc::into_raw(x);
+    /// let (x_ptr, _alloc) = Rc::into_raw_with_allocator(x);
     ///
     /// unsafe {
     ///     // Convert back to an `Rc` to prevent leak.
@@ -1547,7 +1547,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// use std::alloc::System;
     ///
     /// let x: Rc<[u32], _> = Rc::new_in([1, 2, 3], System);
-    /// let x_ptr: *const [u32] = Rc::into_raw(x);
+    /// let x_ptr: *const [u32] = Rc::into_raw_with_allocator(x).0;
     ///
     /// unsafe {
     ///     let x: Rc<[u32; 3], _> = Rc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System);
@@ -1648,7 +1648,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// let five = Rc::new_in(5, System);
     ///
     /// unsafe {
-    ///     let ptr = Rc::into_raw(five);
+    ///     let (ptr, _alloc) = Rc::into_raw_with_allocator(five);
     ///     Rc::increment_strong_count_in(ptr, System);
     ///
     ///     let five = Rc::from_raw_in(ptr, System);
@@ -1694,7 +1694,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     /// let five = Rc::new_in(5, System);
     ///
     /// unsafe {
-    ///     let ptr = Rc::into_raw(five);
+    ///     let (ptr, _alloc) = Rc::into_raw_with_allocator(five);
     ///     Rc::increment_strong_count_in(ptr, System);
     ///
     ///     let five = Rc::from_raw_in(ptr, System);
@@ -3123,6 +3123,39 @@ impl<T: ?Sized> Weak<T> {
     pub unsafe fn from_raw(ptr: *const T) -> Self {
         unsafe { Self::from_raw_in(ptr, Global) }
     }
+
+    /// Consumes the `Weak<T>` and turns it into a raw pointer.
+    ///
+    /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
+    /// one weak reference (the weak count is not modified by this operation). It can be turned
+    /// back into the `Weak<T>` with [`from_raw`].
+    ///
+    /// The same restrictions of accessing the target of the pointer as with
+    /// [`as_ptr`] apply.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::rc::{Rc, Weak};
+    ///
+    /// let strong = Rc::new("hello".to_owned());
+    /// let weak = Rc::downgrade(&strong);
+    /// let raw = weak.into_raw();
+    ///
+    /// assert_eq!(1, Rc::weak_count(&strong));
+    /// assert_eq!("hello", unsafe { &*raw });
+    ///
+    /// drop(unsafe { Weak::from_raw(raw) });
+    /// assert_eq!(0, Rc::weak_count(&strong));
+    /// ```
+    ///
+    /// [`from_raw`]: Weak::from_raw
+    /// [`as_ptr`]: Weak::as_ptr
+    #[must_use = "losing the pointer will leak memory"]
+    #[stable(feature = "weak_into_raw", since = "1.45.0")]
+    pub fn into_raw(self) -> *const T {
+        mem::ManuallyDrop::new(self).as_ptr()
+    }
 }
 
 impl<T: ?Sized, A: Allocator> Weak<T, A> {
@@ -3175,39 +3208,6 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
         }
     }
 
-    /// Consumes the `Weak<T>` and turns it into a raw pointer.
-    ///
-    /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
-    /// one weak reference (the weak count is not modified by this operation). It can be turned
-    /// back into the `Weak<T>` with [`from_raw`].
-    ///
-    /// The same restrictions of accessing the target of the pointer as with
-    /// [`as_ptr`] apply.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::rc::{Rc, Weak};
-    ///
-    /// let strong = Rc::new("hello".to_owned());
-    /// let weak = Rc::downgrade(&strong);
-    /// let raw = weak.into_raw();
-    ///
-    /// assert_eq!(1, Rc::weak_count(&strong));
-    /// assert_eq!("hello", unsafe { &*raw });
-    ///
-    /// drop(unsafe { Weak::from_raw(raw) });
-    /// assert_eq!(0, Rc::weak_count(&strong));
-    /// ```
-    ///
-    /// [`from_raw`]: Weak::from_raw
-    /// [`as_ptr`]: Weak::as_ptr
-    #[must_use = "losing the pointer will leak memory"]
-    #[stable(feature = "weak_into_raw", since = "1.45.0")]
-    pub fn into_raw(self) -> *const T {
-        mem::ManuallyDrop::new(self).as_ptr()
-    }
-
     /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
     ///
     /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 1e3c03977bd..b8925f4544f 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1467,6 +1467,30 @@ impl<T: ?Sized> Arc<T> {
         unsafe { Arc::from_raw_in(ptr, Global) }
     }
 
+    /// Consumes the `Arc`, returning the wrapped pointer.
+    ///
+    /// To avoid a memory leak the pointer must be converted back to an `Arc` using
+    /// [`Arc::from_raw`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::Arc;
+    ///
+    /// let x = Arc::new("hello".to_owned());
+    /// let x_ptr = Arc::into_raw(x);
+    /// assert_eq!(unsafe { &*x_ptr }, "hello");
+    /// # // Prevent leaks for Miri.
+    /// # drop(unsafe { Arc::from_raw(x_ptr) });
+    /// ```
+    #[must_use = "losing the pointer will leak memory"]
+    #[stable(feature = "rc_raw", since = "1.17.0")]
+    #[rustc_never_returns_null_ptr]
+    pub fn into_raw(this: Self) -> *const T {
+        let this = ManuallyDrop::new(this);
+        Self::as_ptr(&*this)
+    }
+
     /// Increments the strong reference count on the `Arc<T>` associated with the
     /// provided pointer by one.
     ///
@@ -1558,30 +1582,6 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
         &this.alloc
     }
 
-    /// Consumes the `Arc`, returning the wrapped pointer.
-    ///
-    /// To avoid a memory leak the pointer must be converted back to an `Arc` using
-    /// [`Arc::from_raw`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::Arc;
-    ///
-    /// let x = Arc::new("hello".to_owned());
-    /// let x_ptr = Arc::into_raw(x);
-    /// assert_eq!(unsafe { &*x_ptr }, "hello");
-    /// # // Prevent leaks for Miri.
-    /// # drop(unsafe { Arc::from_raw(x_ptr) });
-    /// ```
-    #[must_use = "losing the pointer will leak memory"]
-    #[stable(feature = "rc_raw", since = "1.17.0")]
-    #[rustc_never_returns_null_ptr]
-    pub fn into_raw(this: Self) -> *const T {
-        let this = ManuallyDrop::new(this);
-        Self::as_ptr(&*this)
-    }
-
     /// Consumes the `Arc`, returning the wrapped pointer and allocator.
     ///
     /// To avoid a memory leak the pointer must be converted back to an `Arc` using
@@ -1676,7 +1676,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// use std::alloc::System;
     ///
     /// let x = Arc::new_in("hello".to_owned(), System);
-    /// let x_ptr = Arc::into_raw(x);
+    /// let (x_ptr, alloc) = Arc::into_raw_with_allocator(x);
     ///
     /// unsafe {
     ///     // Convert back to an `Arc` to prevent leak.
@@ -1698,7 +1698,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// use std::alloc::System;
     ///
     /// let x: Arc<[u32], _> = Arc::new_in([1, 2, 3], System);
-    /// let x_ptr: *const [u32] = Arc::into_raw(x);
+    /// let x_ptr: *const [u32] = Arc::into_raw_with_allocator(x).0;
     ///
     /// unsafe {
     ///     let x: Arc<[u32; 3], _> = Arc::from_raw_in(x_ptr.cast::<[u32; 3]>(), System);
@@ -1850,7 +1850,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// let five = Arc::new_in(5, System);
     ///
     /// unsafe {
-    ///     let ptr = Arc::into_raw(five);
+    ///     let (ptr, _alloc) = Arc::into_raw_with_allocator(five);
     ///     Arc::increment_strong_count_in(ptr, System);
     ///
     ///     // This assertion is deterministic because we haven't shared
@@ -1899,7 +1899,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     /// let five = Arc::new_in(5, System);
     ///
     /// unsafe {
-    ///     let ptr = Arc::into_raw(five);
+    ///     let (ptr, _alloc) = Arc::into_raw_with_allocator(five);
     ///     Arc::increment_strong_count_in(ptr, System);
     ///
     ///     // Those assertions are deterministic because we haven't shared
@@ -2863,6 +2863,39 @@ impl<T: ?Sized> Weak<T> {
     pub unsafe fn from_raw(ptr: *const T) -> Self {
         unsafe { Weak::from_raw_in(ptr, Global) }
     }
+
+    /// Consumes the `Weak<T>` and turns it into a raw pointer.
+    ///
+    /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
+    /// one weak reference (the weak count is not modified by this operation). It can be turned
+    /// back into the `Weak<T>` with [`from_raw`].
+    ///
+    /// The same restrictions of accessing the target of the pointer as with
+    /// [`as_ptr`] apply.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Weak};
+    ///
+    /// let strong = Arc::new("hello".to_owned());
+    /// let weak = Arc::downgrade(&strong);
+    /// let raw = weak.into_raw();
+    ///
+    /// assert_eq!(1, Arc::weak_count(&strong));
+    /// assert_eq!("hello", unsafe { &*raw });
+    ///
+    /// drop(unsafe { Weak::from_raw(raw) });
+    /// assert_eq!(0, Arc::weak_count(&strong));
+    /// ```
+    ///
+    /// [`from_raw`]: Weak::from_raw
+    /// [`as_ptr`]: Weak::as_ptr
+    #[must_use = "losing the pointer will leak memory"]
+    #[stable(feature = "weak_into_raw", since = "1.45.0")]
+    pub fn into_raw(self) -> *const T {
+        ManuallyDrop::new(self).as_ptr()
+    }
 }
 
 impl<T: ?Sized, A: Allocator> Weak<T, A> {
@@ -2915,39 +2948,6 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
         }
     }
 
-    /// Consumes the `Weak<T>` and turns it into a raw pointer.
-    ///
-    /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
-    /// one weak reference (the weak count is not modified by this operation). It can be turned
-    /// back into the `Weak<T>` with [`from_raw`].
-    ///
-    /// The same restrictions of accessing the target of the pointer as with
-    /// [`as_ptr`] apply.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::{Arc, Weak};
-    ///
-    /// let strong = Arc::new("hello".to_owned());
-    /// let weak = Arc::downgrade(&strong);
-    /// let raw = weak.into_raw();
-    ///
-    /// assert_eq!(1, Arc::weak_count(&strong));
-    /// assert_eq!("hello", unsafe { &*raw });
-    ///
-    /// drop(unsafe { Weak::from_raw(raw) });
-    /// assert_eq!(0, Arc::weak_count(&strong));
-    /// ```
-    ///
-    /// [`from_raw`]: Weak::from_raw
-    /// [`as_ptr`]: Weak::as_ptr
-    #[must_use = "losing the pointer will leak memory"]
-    #[stable(feature = "weak_into_raw", since = "1.45.0")]
-    pub fn into_raw(self) -> *const T {
-        ManuallyDrop::new(self).as_ptr()
-    }
-
     /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
     ///
     /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 5bd82560da7..c8341750f4d 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -761,6 +761,88 @@ impl<T> Vec<T> {
     pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
         PeekMut::new(self)
     }
+
+    /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity)`.
+    ///
+    /// Returns the raw pointer to the underlying data, the length of
+    /// the vector (in elements), and the allocated capacity of the
+    /// data (in elements). These are the same arguments in the same
+    /// order as the arguments to [`from_raw_parts`].
+    ///
+    /// After calling this function, the caller is responsible for the
+    /// memory previously managed by the `Vec`. The only way to do
+    /// this is to convert the raw pointer, length, and capacity back
+    /// into a `Vec` with the [`from_raw_parts`] function, allowing
+    /// the destructor to perform the cleanup.
+    ///
+    /// [`from_raw_parts`]: Vec::from_raw_parts
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_into_raw_parts)]
+    /// let v: Vec<i32> = vec![-1, 0, 1];
+    ///
+    /// let (ptr, len, cap) = v.into_raw_parts();
+    ///
+    /// let rebuilt = unsafe {
+    ///     // We can now make changes to the components, such as
+    ///     // transmuting the raw pointer to a compatible type.
+    ///     let ptr = ptr as *mut u32;
+    ///
+    ///     Vec::from_raw_parts(ptr, len, cap)
+    /// };
+    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
+    /// ```
+    #[must_use = "losing the pointer will leak memory"]
+    #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
+    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
+        let mut me = ManuallyDrop::new(self);
+        (me.as_mut_ptr(), me.len(), me.capacity())
+    }
+
+    #[doc(alias = "into_non_null_parts")]
+    /// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity)`.
+    ///
+    /// Returns the `NonNull` pointer to the underlying data, the length of
+    /// the vector (in elements), and the allocated capacity of the
+    /// data (in elements). These are the same arguments in the same
+    /// order as the arguments to [`from_parts`].
+    ///
+    /// After calling this function, the caller is responsible for the
+    /// memory previously managed by the `Vec`. The only way to do
+    /// this is to convert the `NonNull` pointer, length, and capacity back
+    /// into a `Vec` with the [`from_parts`] function, allowing
+    /// the destructor to perform the cleanup.
+    ///
+    /// [`from_parts`]: Vec::from_parts
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_into_raw_parts, box_vec_non_null)]
+    ///
+    /// let v: Vec<i32> = vec![-1, 0, 1];
+    ///
+    /// let (ptr, len, cap) = v.into_parts();
+    ///
+    /// let rebuilt = unsafe {
+    ///     // We can now make changes to the components, such as
+    ///     // transmuting the raw pointer to a compatible type.
+    ///     let ptr = ptr.cast::<u32>();
+    ///
+    ///     Vec::from_parts(ptr, len, cap)
+    /// };
+    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
+    /// ```
+    #[must_use = "losing the pointer will leak memory"]
+    #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
+    // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
+    pub fn into_parts(self) -> (NonNull<T>, usize, usize) {
+        let (ptr, len, capacity) = self.into_raw_parts();
+        // SAFETY: A `Vec` always has a non-null pointer.
+        (unsafe { NonNull::new_unchecked(ptr) }, len, capacity)
+    }
 }
 
 impl<T, A: Allocator> Vec<T, A> {
@@ -1095,88 +1177,6 @@ impl<T, A: Allocator> Vec<T, A> {
         unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }
     }
 
-    /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity)`.
-    ///
-    /// Returns the raw pointer to the underlying data, the length of
-    /// the vector (in elements), and the allocated capacity of the
-    /// data (in elements). These are the same arguments in the same
-    /// order as the arguments to [`from_raw_parts`].
-    ///
-    /// After calling this function, the caller is responsible for the
-    /// memory previously managed by the `Vec`. The only way to do
-    /// this is to convert the raw pointer, length, and capacity back
-    /// into a `Vec` with the [`from_raw_parts`] function, allowing
-    /// the destructor to perform the cleanup.
-    ///
-    /// [`from_raw_parts`]: Vec::from_raw_parts
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(vec_into_raw_parts)]
-    /// let v: Vec<i32> = vec![-1, 0, 1];
-    ///
-    /// let (ptr, len, cap) = v.into_raw_parts();
-    ///
-    /// let rebuilt = unsafe {
-    ///     // We can now make changes to the components, such as
-    ///     // transmuting the raw pointer to a compatible type.
-    ///     let ptr = ptr as *mut u32;
-    ///
-    ///     Vec::from_raw_parts(ptr, len, cap)
-    /// };
-    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
-    /// ```
-    #[must_use = "losing the pointer will leak memory"]
-    #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
-    pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
-        let mut me = ManuallyDrop::new(self);
-        (me.as_mut_ptr(), me.len(), me.capacity())
-    }
-
-    #[doc(alias = "into_non_null_parts")]
-    /// Decomposes a `Vec<T>` into its raw components: `(NonNull pointer, length, capacity)`.
-    ///
-    /// Returns the `NonNull` pointer to the underlying data, the length of
-    /// the vector (in elements), and the allocated capacity of the
-    /// data (in elements). These are the same arguments in the same
-    /// order as the arguments to [`from_parts`].
-    ///
-    /// After calling this function, the caller is responsible for the
-    /// memory previously managed by the `Vec`. The only way to do
-    /// this is to convert the `NonNull` pointer, length, and capacity back
-    /// into a `Vec` with the [`from_parts`] function, allowing
-    /// the destructor to perform the cleanup.
-    ///
-    /// [`from_parts`]: Vec::from_parts
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(vec_into_raw_parts, box_vec_non_null)]
-    ///
-    /// let v: Vec<i32> = vec![-1, 0, 1];
-    ///
-    /// let (ptr, len, cap) = v.into_parts();
-    ///
-    /// let rebuilt = unsafe {
-    ///     // We can now make changes to the components, such as
-    ///     // transmuting the raw pointer to a compatible type.
-    ///     let ptr = ptr.cast::<u32>();
-    ///
-    ///     Vec::from_parts(ptr, len, cap)
-    /// };
-    /// assert_eq!(rebuilt, [4294967295, 0, 1]);
-    /// ```
-    #[must_use = "losing the pointer will leak memory"]
-    #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
-    // #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")]
-    pub fn into_parts(self) -> (NonNull<T>, usize, usize) {
-        let (ptr, len, capacity) = self.into_raw_parts();
-        // SAFETY: A `Vec` always has a non-null pointer.
-        (unsafe { NonNull::new_unchecked(ptr) }, len, capacity)
-    }
-
     /// Decomposes a `Vec<T>` into its raw components: `(pointer, length, capacity, allocator)`.
     ///
     /// Returns the raw pointer to the underlying data, the length of the vector (in elements),
@@ -3031,6 +3031,61 @@ impl<T, A: Allocator> Vec<T, A> {
             (initialized, spare, &mut self.len)
         }
     }
+
+    /// Groups every `N` elements in the `Vec<T>` into chunks to produce a `Vec<[T; N]>`, dropping
+    /// elements in the remainder. `N` must be greater than zero.
+    ///
+    /// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the
+    /// nearest multiple with a reallocation or deallocation.
+    ///
+    /// This function can be used to reverse [`Vec::into_flattened`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_into_chunks)]
+    ///
+    /// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7];
+    /// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]);
+    ///
+    /// let vec = vec![0, 1, 2, 3];
+    /// let chunks: Vec<[u8; 10]> = vec.into_chunks();
+    /// assert!(chunks.is_empty());
+    ///
+    /// let flat = vec![0; 8 * 8 * 8];
+    /// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks();
+    /// assert_eq!(reshaped.len(), 1);
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "vec_into_chunks", issue = "142137")]
+    pub fn into_chunks<const N: usize>(mut self) -> Vec<[T; N], A> {
+        const {
+            assert!(N != 0, "chunk size must be greater than zero");
+        }
+
+        let (len, cap) = (self.len(), self.capacity());
+
+        let len_remainder = len % N;
+        if len_remainder != 0 {
+            self.truncate(len - len_remainder);
+        }
+
+        let cap_remainder = cap % N;
+        if !T::IS_ZST && cap_remainder != 0 {
+            self.buf.shrink_to_fit(cap - cap_remainder);
+        }
+
+        let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc();
+
+        // SAFETY:
+        // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
+        // - `[T; N]` has the same alignment as `T`
+        // - `size_of::<[T; N]>() * cap / N == size_of::<T>() * cap`
+        // - `len / N <= cap / N` because `len <= cap`
+        // - the allocated memory consists of `len / N` valid values of type `[T; N]`
+        // - `cap / N` fits the size of the allocated memory after shrinking
+        unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) }
+    }
 }
 
 impl<T: Clone, A: Allocator> Vec<T, A> {
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index 2016ece007e..99268d6182f 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -61,4 +61,71 @@ impl bool {
     pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
         if self { Some(f()) } else { None }
     }
+
+    /// Returns `Ok(())` if the `bool` is [`true`](../std/keyword.true.html),
+    /// or `Err(err)` otherwise.
+    ///
+    /// Arguments passed to `ok_or` are eagerly evaluated; if you are
+    /// passing the result of a function call, it is recommended to use
+    /// [`ok_or_else`], which is lazily evaluated.
+    ///
+    /// [`ok_or_else`]: bool::ok_or_else
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(bool_to_result)]
+    ///
+    /// assert_eq!(false.ok_or(0), Err(0));
+    /// assert_eq!(true.ok_or(0), Ok(()));
+    /// ```
+    ///
+    /// ```
+    /// #![feature(bool_to_result)]
+    ///
+    /// let mut a = 0;
+    /// let mut function_with_side_effects = || { a += 1; };
+    ///
+    /// assert!(true.ok_or(function_with_side_effects()).is_ok());
+    /// assert!(false.ok_or(function_with_side_effects()).is_err());
+    ///
+    /// // `a` is incremented twice because the value passed to `ok_or` is
+    /// // evaluated eagerly.
+    /// assert_eq!(a, 2);
+    /// ```
+    #[unstable(feature = "bool_to_result", issue = "142748")]
+    #[inline]
+    pub fn ok_or<E>(self, err: E) -> Result<(), E> {
+        if self { Ok(()) } else { Err(err) }
+    }
+
+    /// Returns `Ok(())` if the `bool` is [`true`](../std/keyword.true.html),
+    /// or `Err(f())` otherwise.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(bool_to_result)]
+    ///
+    /// assert_eq!(false.ok_or_else(|| 0), Err(0));
+    /// assert_eq!(true.ok_or_else(|| 0), Ok(()));
+    /// ```
+    ///
+    /// ```
+    /// #![feature(bool_to_result)]
+    ///
+    /// let mut a = 0;
+    ///
+    /// assert!(true.ok_or_else(|| { a += 1; }).is_ok());
+    /// assert!(false.ok_or_else(|| { a += 1; }).is_err());
+    ///
+    /// // `a` is incremented once because the closure is evaluated lazily by
+    /// // `ok_or_else`.
+    /// assert_eq!(a, 1);
+    /// ```
+    #[unstable(feature = "bool_to_result", issue = "142748")]
+    #[inline]
+    pub fn ok_or_else<E, F: FnOnce() -> E>(self, f: F) -> Result<(), E> {
+        if self { Ok(()) } else { Err(f()) }
+    }
 }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 0aa8f47462d..b1ca3701fa5 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1449,7 +1449,6 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
     /// check `==` and `<` separately to do rather than needing to calculate
     /// (then optimize out) the three-way `Ordering` result.
     #[inline]
-    #[must_use]
     // Added to improve the behaviour of tuples; not necessarily stabilization-track.
     #[unstable(feature = "partial_ord_chaining_methods", issue = "none")]
     #[doc(hidden)]
@@ -1459,7 +1458,6 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
 
     /// Same as `__chaining_lt`, but for `<=` instead of `<`.
     #[inline]
-    #[must_use]
     #[unstable(feature = "partial_ord_chaining_methods", issue = "none")]
     #[doc(hidden)]
     fn __chaining_le(&self, other: &Rhs) -> ControlFlow<bool> {
@@ -1468,7 +1466,6 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
 
     /// Same as `__chaining_lt`, but for `>` instead of `<`.
     #[inline]
-    #[must_use]
     #[unstable(feature = "partial_ord_chaining_methods", issue = "none")]
     #[doc(hidden)]
     fn __chaining_gt(&self, other: &Rhs) -> ControlFlow<bool> {
@@ -1477,7 +1474,6 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
 
     /// Same as `__chaining_lt`, but for `>=` instead of `<`.
     #[inline]
-    #[must_use]
     #[unstable(feature = "partial_ord_chaining_methods", issue = "none")]
     #[doc(hidden)]
     fn __chaining_ge(&self, other: &Rhs) -> ControlFlow<bool> {
diff --git a/library/core/src/error.rs b/library/core/src/error.rs
index bfa392003b9..7f5c6ac42bc 100644
--- a/library/core/src/error.rs
+++ b/library/core/src/error.rs
@@ -347,7 +347,7 @@ impl dyn Error {
     /// let b = B(Some(Box::new(A)));
     ///
     /// // let err : Box<Error> = b.into(); // or
-    /// let err = &b as &(dyn Error);
+    /// let err = &b as &dyn Error;
     ///
     /// let mut iter = err.sources();
     ///
diff --git a/library/core/src/ffi/c_char.md b/library/core/src/ffi/c_char.md
index b262a3663b3..119b739a39e 100644
--- a/library/core/src/ffi/c_char.md
+++ b/library/core/src/ffi/c_char.md
@@ -1,6 +1,6 @@
 Equivalent to C's `char` type.
 
-[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addresses memory with 8-bit bytes.
+[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addressed memory with 8-bit bytes.
 
 C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See `CStr` for more information.
 
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 2be8d37bbee..c593737af8a 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2867,7 +2867,7 @@ macro_rules! tuple {
         maybe_tuple_doc! {
             $($name)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($name:Debug),+> Debug for ($($name,)+) where last_type!($($name,)+): ?Sized {
+            impl<$($name:Debug),+> Debug for ($($name,)+) {
                 #[allow(non_snake_case, unused_assignments)]
                 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
                     let mut builder = f.debug_tuple("");
@@ -2898,11 +2898,6 @@ macro_rules! maybe_tuple_doc {
     };
 }
 
-macro_rules! last_type {
-    ($a:ident,) => { $a };
-    ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
-}
-
 tuple! { E, D, C, B, A, Z, Y, X, W, V, U, T, }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index 42af595ae41..80f462263a5 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -589,7 +589,7 @@ impl fmt::Display for i128 {
 }
 
 impl u128 {
-    /// Format optimized for u128. Computation of 128 bits is limited by proccessing
+    /// Format optimized for u128. Computation of 128 bits is limited by processing
     /// in batches of 16 decimals at a time.
     #[doc(hidden)]
     #[unstable(
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index efda64791d4..a10c85640bb 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -886,7 +886,7 @@ mod impls {
             maybe_tuple_doc! {
                 $($name)+ @
                 #[stable(feature = "rust1", since = "1.0.0")]
-                impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
+                impl<$($name: Hash),+> Hash for ($($name,)+) {
                     #[allow(non_snake_case)]
                     #[inline]
                     fn hash<S: Hasher>(&self, state: &mut S) {
@@ -912,11 +912,6 @@ mod impls {
         };
     }
 
-    macro_rules! last_type {
-        ($a:ident,) => { $a };
-        ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
-    }
-
     impl_hash_tuple! {}
     impl_hash_tuple! { T }
     impl_hash_tuple! { T B }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 4250de9fb2b..ab99492638e 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -459,7 +459,7 @@ pub const fn unlikely(b: bool) -> bool {
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 ///
-/// The public form of this instrinsic is [`core::hint::select_unpredictable`].
+/// The public form of this intrinsic is [`core::hint::select_unpredictable`].
 /// However unlike the public form, the intrinsic will not drop the value that
 /// is not selected.
 #[unstable(feature = "core_intrinsics", issue = "none")]
@@ -472,7 +472,8 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
 }
 
 /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
-/// This will statically either panic, or do nothing.
+/// This will statically either panic, or do nothing. It does not *guarantee* to ever panic,
+/// and should only be called if an assertion failure will imply language UB in the following code.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic_const_stable_indirect]
@@ -481,7 +482,9 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
 pub const fn assert_inhabited<T>();
 
 /// A guard for unsafe functions that cannot ever be executed if `T` does not permit
-/// zero-initialization: This will statically either panic, or do nothing.
+/// zero-initialization: This will statically either panic, or do nothing. It does not *guarantee*
+/// to ever panic, and should only be called if an assertion failure will imply language UB in the
+/// following code.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic_const_stable_indirect]
@@ -489,7 +492,9 @@ pub const fn assert_inhabited<T>();
 #[rustc_intrinsic]
 pub const fn assert_zero_valid<T>();
 
-/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
+/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. It does
+/// not *guarantee* to ever panic, and should only be called if an assertion failure will imply
+/// language UB in the following code.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic_const_stable_indirect]
@@ -2290,7 +2295,7 @@ where
 /// used inside the `if const`.
 /// Note that the two arms of this `if` really each become their own function, which is why the
 /// macro supports setting attributes for those functions. The runtime function is always
-/// markes as `#[inline]`.
+/// marked as `#[inline]`.
 ///
 /// See [`const_eval_select()`] for the rules and requirements around that intrinsic.
 pub(crate) macro const_eval_select {
@@ -2530,7 +2535,7 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
 /// Returns whether we should perform contract-checking at runtime.
 ///
 /// This is meant to be similar to the ub_checks intrinsic, in terms
-/// of not prematurely commiting at compile-time to whether contract
+/// of not prematurely committing at compile-time to whether contract
 /// checking is turned on, so that we can specify contracts in libstd
 /// and let an end user opt into turning them on.
 #[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 11533ab6aa4..19488082cc3 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -160,7 +160,7 @@ pub unsafe fn simd_funnel_shl<T>(a: T, b: T, shift: T) -> T;
 #[rustc_nounwind]
 pub unsafe fn simd_funnel_shr<T>(a: T, b: T, shift: T) -> T;
 
-/// "Ands" vectors elementwise.
+/// "And"s vectors elementwise.
 ///
 /// `T` must be a vector of integers.
 #[rustc_intrinsic]
@@ -522,7 +522,7 @@ pub unsafe fn simd_reduce_max<T, U>(x: T) -> U;
 #[rustc_nounwind]
 pub unsafe fn simd_reduce_min<T, U>(x: T) -> U;
 
-/// Logical "ands" all elements together.
+/// Logical "and"s all elements together.
 ///
 /// `T` must be a vector of integers or floats.
 ///
diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index 6bd9c18e00b..854e03cf182 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -281,7 +281,7 @@ impl<'a> BorrowedCursor<'a> {
     /// Panics if there are less than `n` bytes initialized.
     #[inline]
     pub fn advance(&mut self, n: usize) -> &mut Self {
-        // The substraction cannot underflow by invariant of this type.
+        // The subtraction cannot underflow by invariant of this type.
         assert!(n <= self.buf.init - self.buf.filled);
 
         self.buf.filled += n;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 6e160eddecb..2f701171505 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -89,7 +89,7 @@
 #![allow(internal_features)]
 #![deny(ffi_unwind_calls)]
 #![warn(unreachable_pub)]
-// Do not check link redundancy on bootstraping phase
+// Do not check link redundancy on bootstrapping phase
 #![allow(rustdoc::redundant_explicit_links)]
 #![warn(rustdoc::unescaped_backticks)]
 //
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 0cc5640941a..67f95a02af3 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -19,6 +19,9 @@ use crate::fmt::Debug;
 use crate::hash::{Hash, Hasher};
 use crate::pin::UnsafePinned;
 
+// NOTE: for consistent error messages between `core` and `minicore`, all `diagnostic` attributes
+// should be replicated exactly in `minicore` (if `minicore` defines the item).
+
 /// Implements a given marker trait for multiple types at the same time.
 ///
 /// The basic syntax looks like this:
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 63a479ed8dd..fc35e54bb0d 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -616,7 +616,9 @@ impl<T> MaybeUninit<T> {
         // This also means that `self` must be a `value` variant.
         unsafe {
             intrinsics::assert_inhabited::<T>();
-            ManuallyDrop::into_inner(self.value)
+            // We do this via a raw ptr read instead of `ManuallyDrop::into_inner` so that there's
+            // no trace of `ManuallyDrop` in Miri's error messages here.
+            (&raw const self.value).cast::<T>().read()
         }
     }
 
diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs
index 5bf0faf0bc9..21aabdc8add 100644
--- a/library/core/src/num/dec2flt/float.rs
+++ b/library/core/src/num/dec2flt/float.rs
@@ -109,7 +109,7 @@ pub trait RawFloat:
 
     /// Round-to-even only happens for negative values of q
     /// when q ≥ −4 in the 64-bit case and when q ≥ −17 in
-    /// the 32-bitcase.
+    /// the 32-bit case.
     ///
     /// When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we
     /// have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have
@@ -119,7 +119,7 @@ pub trait RawFloat:
     /// so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case)
     /// or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64
     /// (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11
-    /// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase).
+    /// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bit case).
     ///
     /// Thus we have that we only need to round ties to even when
     /// we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10]
@@ -143,7 +143,7 @@ pub trait RawFloat:
     /// smaller than `10^SMALLEST_POWER_OF_TEN`, which will round to zero.
     ///
     /// The smallest power of ten is represented by `⌊log10(2^-n / (2^64 - 1))⌋`, where `n` is
-    /// the smallest power of two. The `2^64 - 1)` denomenator comes from the number of values
+    /// the smallest power of two. The `2^64 - 1)` denominator comes from the number of values
     /// that are representable by the intermediate storage format. I don't actually know _why_
     /// the storage format is relevant here.
     ///
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 6ef2fdd14c1..a5242d60bf1 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -79,7 +79,7 @@ pub struct ParseIntError {
 /// # }
 /// ```
 #[stable(feature = "int_error_matching", since = "1.55.0")]
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
 #[non_exhaustive]
 pub enum IntErrorKind {
     /// Value being parsed is empty.
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 079032f2f96..9cadbd47ab6 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2572,7 +2572,7 @@ macro_rules! uint_impl {
             if size_of::<Self>() == 1 {
                 // Trick LLVM into generating the psadbw instruction when SSE2
                 // is available and this function is autovectorized for u8's.
-                (self as i32).wrapping_sub(other as i32).abs() as Self
+                (self as i32).wrapping_sub(other as i32).unsigned_abs() as Self
             } else {
                 if self < other {
                     other - self
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index 1935268cda8..ad3b6439a61 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -1211,7 +1211,7 @@ pub enum OneSidedRangeBound {
 /// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded`
 /// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`.
 #[unstable(feature = "one_sided_range", issue = "69780")]
-pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {
+pub trait OneSidedRange<T>: RangeBounds<T> {
     /// An internal-only helper function for `split_off` and
     /// `split_off_mut` that returns the bound of the one-sided range.
     fn bound(self) -> (OneSidedRangeBound, T);
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index b6d5f848ef0..3ca6feb679b 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -792,7 +792,7 @@
 //!
 //! 1.  *Structural [`Unpin`].* A struct can be [`Unpin`] only if all of its
 //!     structurally-pinned fields are, too. This is [`Unpin`]'s behavior by default.
-//!     However, as a libray author, it is your responsibility not to write something like
+//!     However, as a library author, it is your responsibility not to write something like
 //!     <code>impl\<T> [Unpin] for Struct\<T> {}</code> and then offer a method that provides
 //!     structural pinning to an inner field of `T`, which may not be [`Unpin`]! (Adding *any*
 //!     projection operation requires unsafe code, so the fact that [`Unpin`] is a safe trait does
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 800eb74babb..27b0c6830db 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -29,7 +29,7 @@ impl<T: PointeeSized> *const T {
             if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] {
                 match (ptr).guaranteed_eq(null_mut()) {
                     Some(res) => res,
-                    // To remain maximally convervative, we stop execution when we don't
+                    // To remain maximally conservative, we stop execution when we don't
                     // know whether the pointer is null or not.
                     // We can *not* return `false` here, that would be unsound in `NonNull::new`!
                     None => panic!("null-ness of this pointer cannot be determined in const context"),
@@ -49,7 +49,7 @@ impl<T: PointeeSized> *const T {
         self as _
     }
 
-    /// Try to cast to a pointer of another type by checking aligment.
+    /// Try to cast to a pointer of another type by checking alignment.
     ///
     /// If the pointer is properly aligned to the target type, it will be
     /// cast to the target type. Otherwise, `None` is returned.
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 6b436184f20..73efdf04454 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -32,7 +32,7 @@ impl<T: PointeeSized> *mut T {
         self as _
     }
 
-    /// Try to cast to a pointer of another type by checking aligment.
+    /// Try to cast to a pointer of another type by checking alignment.
     ///
     /// If the pointer is properly aligned to the target type, it will be
     /// cast to the target type. Otherwise, `None` is returned.
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index ea650b810b7..c26c3a32ef3 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -497,7 +497,7 @@ impl<T: PointeeSized> NonNull<T> {
         unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
     }
 
-    /// Try to cast to a pointer of another type by checking aligment.
+    /// Try to cast to a pointer of another type by checking alignment.
     ///
     /// If the pointer is properly aligned to the target type, it will be
     /// cast to the target type. Otherwise, `None` is returned.
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 6327c41f052..9cf08e74ff6 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,7 +1,7 @@
 // See core/src/primitive_docs.rs for documentation.
 
 use crate::cmp::Ordering::{self, *};
-use crate::marker::{ConstParamTy_, PointeeSized, StructuralPartialEq, UnsizedConstParamTy};
+use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy};
 use crate::ops::ControlFlow::{self, Break, Continue};
 use crate::random::{Random, RandomSource};
 
@@ -24,10 +24,7 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: PartialEq),+> PartialEq for ($($T,)+)
-            where
-                last_type!($($T,)+): PointeeSized
-            {
+            impl<$($T: PartialEq),+> PartialEq for ($($T,)+) {
                 #[inline]
                 fn eq(&self, other: &($($T,)+)) -> bool {
                     $( ${ignore($T)} self.${index()} == other.${index()} )&&+
@@ -43,8 +40,6 @@ macro_rules! tuple_impls {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<$($T: Eq),+> Eq for ($($T,)+)
-            where
-                last_type!($($T,)+): PointeeSized
             {}
         }
 
@@ -73,8 +68,6 @@ macro_rules! tuple_impls {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
-            where
-                last_type!($($T,)+): PointeeSized
             {
                 #[inline]
                 fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
@@ -119,8 +112,6 @@ macro_rules! tuple_impls {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<$($T: Ord),+> Ord for ($($T,)+)
-            where
-                last_type!($($T,)+): PointeeSized
             {
                 #[inline]
                 fn cmp(&self, other: &($($T,)+)) -> Ordering {
@@ -245,9 +236,4 @@ macro_rules! lexical_cmp {
     ($a:expr, $b:expr) => { ($a).cmp(&$b) };
 }
 
-macro_rules! last_type {
-    ($a:ident,) => { $a };
-    ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
-}
-
 tuple_impls!(E D C B A Z Y X W V U T);
diff --git a/library/coretests/tests/bool.rs b/library/coretests/tests/bool.rs
index bcd6dc2abac..eb5f0f50663 100644
--- a/library/coretests/tests/bool.rs
+++ b/library/coretests/tests/bool.rs
@@ -105,3 +105,11 @@ fn test_bool_to_option() {
     assert_eq!(D, Some(0));
     */
 }
+
+#[test]
+fn test_bool_to_result() {
+    assert_eq!(false.ok_or(0), Err(0));
+    assert_eq!(true.ok_or(0), Ok(()));
+    assert_eq!(false.ok_or_else(|| 0), Err(0));
+    assert_eq!(true.ok_or_else(|| 0), Ok(()));
+}
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 0c54609260f..fdef736c0c0 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -11,6 +11,7 @@
 #![feature(async_iter_from_iter)]
 #![feature(async_iterator)]
 #![feature(bigint_helper_methods)]
+#![feature(bool_to_result)]
 #![feature(bstr)]
 #![feature(cfg_target_has_reliable_f16_f128)]
 #![feature(char_max_len)]
diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs
index 2407ba50ca3..193d5887749 100644
--- a/library/coretests/tests/num/dec2flt/float.rs
+++ b/library/coretests/tests/num/dec2flt/float.rs
@@ -23,7 +23,7 @@ fn test_f16_integer_decode() {
 fn test_f32_integer_decode() {
     assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
     assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
-    // Set 2^100 directly instead of using powf, because it doesn't guarentee precision
+    // Set 2^100 directly instead of using powf, because it doesn't guarantee precision
     assert_eq!(1.2676506e30_f32.integer_decode(), (8388608, 77, 1));
     assert_eq!(0f32.integer_decode(), (0, -150, 1));
     assert_eq!((-0f32).integer_decode(), (0, -150, -1));
@@ -40,7 +40,7 @@ fn test_f32_integer_decode() {
 fn test_f64_integer_decode() {
     assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
     assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
-    // Set 2^100 directly instead of using powf, because it doesn't guarentee precision
+    // Set 2^100 directly instead of using powf, because it doesn't guarantee precision
     assert_eq!(1.2676506002282294e30_f64.integer_decode(), (4503599627370496, 48, 1));
     assert_eq!(0f64.integer_decode(), (0, -1075, 1));
     assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml
index bd318fc2f9e..1ddc112380f 100644
--- a/library/rustc-std-workspace-core/Cargo.toml
+++ b/library/rustc-std-workspace-core/Cargo.toml
@@ -1,3 +1,5 @@
+cargo-features = ["public-dependency"]
+
 [package]
 name = "rustc-std-workspace-core"
 version = "1.99.0"
@@ -11,5 +13,7 @@ edition = "2024"
 path = "lib.rs"
 
 [dependencies]
-core = { path = "../core" }
-compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["compiler-builtins"] }
+core = { path = "../core", public = true }
+compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = [
+  "compiler-builtins",
+] }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index d9902d41928..72ad7c244ee 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -4,6 +4,27 @@
 //! filesystem. All methods in this module represent cross-platform filesystem
 //! operations. Extra platform-specific functionality can be found in the
 //! extension traits of `std::os::$platform`.
+//!
+//! # Time of Check to Time of Use (TOCTOU)
+//!
+//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use"
+//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions)
+//! and then uses the result of that check to make a decision, but the condition may have changed
+//! between the check and the use.
+//!
+//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to
+//! TOCTOU - another process could create the file between your check and creation attempt.
+//!
+//! Another example is with symbolic links: when removing a directory, if another process replaces
+//! the directory with a symbolic link between the check and the removal operation, the removal
+//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use
+//! atomic operations to prevent such race conditions.
+//!
+//! To avoid TOCTOU issues:
+//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by
+//! changes made by other processes.
+//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating).
+//! - Keep file open for the duration of operations.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
@@ -548,13 +569,14 @@ impl File {
     /// non-exhaustive list of likely errors.
     ///
     /// This option is useful because it is atomic. Otherwise between checking whether a file
-    /// exists and creating a new one, the file may have been created by another process (a TOCTOU
+    /// exists and creating a new one, the file may have been created by another process (a [TOCTOU]
     /// race condition / attack).
     ///
     /// This can also be written using
     /// `File::options().read(true).write(true).create_new(true).open(...)`.
     ///
     /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists
+    /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
     ///
     /// # Examples
     ///
@@ -1610,7 +1632,7 @@ impl OpenOptions {
     ///
     /// This option is useful because it is atomic. Otherwise between checking
     /// whether a file exists and creating a new one, the file may have been
-    /// created by another process (a TOCTOU race condition / attack).
+    /// created by another process (a [TOCTOU] race condition / attack).
     ///
     /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
     /// ignored.
@@ -1621,6 +1643,7 @@ impl OpenOptions {
     /// [`.create()`]: OpenOptions::create
     /// [`.truncate()`]: OpenOptions::truncate
     /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists
+    /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
     ///
     /// # Examples
     ///
@@ -2954,17 +2977,17 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`.
 ///
 /// ## Time-of-check to time-of-use (TOCTOU) race conditions
-/// On a few platforms there is no way to remove a directory's contents without following symlinks
-/// unless you perform a check and then operate on paths based on that directory.
-/// This allows concurrently-running code to replace the directory with a symlink after the check,
-/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race.
-/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms
-/// except the following. It should not be used in security-sensitive contexts on these platforms:
-/// - Miri: Even when emulating targets where the underlying implementation will protect against
-/// TOCTOU races, Miri will not do so.
-/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement
-/// the required platform support to do so.
+/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou).
+///
+/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default.
+/// However, on the following platforms, this protection is not provided and the function should
+/// not be used in security-sensitive contexts:
+/// - **Miri**: Even when emulating targets where the underlying implementation will protect against
+///   TOCTOU races, Miri will not do so.
+/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement
+///   the required platform support to do so.
 ///
+/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
 /// [changes]: io#platform-specific-behavior
 ///
 /// # Errors
@@ -3091,7 +3114,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
 /// On UNIX-like systems, this function will update the permission bits
 /// of the file pointed to by the symlink.
 ///
-/// Note that this behavior can lead to privalage escalation vulnerabilites,
+/// Note that this behavior can lead to privalage escalation vulnerabilities,
 /// where the ability to create a symlink in one directory allows you to
 /// cause the permissions of another file or directory to be modified.
 ///
@@ -3238,7 +3261,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
 /// permission is denied on one of the parent directories.
 ///
 /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
-/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
+/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
 /// where those bugs are not an issue.
 ///
 /// # Examples
@@ -3251,6 +3274,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
 /// ```
 ///
 /// [`Path::exists`]: crate::path::Path::exists
+/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
 #[stable(feature = "fs_try_exists", since = "1.81.0")]
 #[inline]
 pub fn exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 3f4fe2e56ec..466b134d8fa 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -385,7 +385,7 @@ pub trait ChildExt: Sealed {
     /// # Errors
     ///
     /// This function will return an error if the signal is invalid. The integer values associated
-    /// with signals are implemenation-specific, so it's encouraged to use a crate that provides
+    /// with signals are implementation-specific, so it's encouraged to use a crate that provides
     /// posix bindings.
     ///
     /// # Examples
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index b734d2b324c..0ce20a143df 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3127,7 +3127,7 @@ impl Path {
     /// Returns `true` if the path points at an existing entity.
     ///
     /// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
-    /// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs.
+    /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs.
     ///
     /// This function will traverse symbolic links to query information about the
     /// destination file.
@@ -3148,6 +3148,7 @@ impl Path {
     /// check errors, call [`Path::try_exists`].
     ///
     /// [`try_exists()`]: Self::try_exists
+    /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
     #[stable(feature = "path_ext", since = "1.5.0")]
     #[must_use]
     #[inline]
@@ -3167,7 +3168,7 @@ impl Path {
     /// permission is denied on one of the parent directories.
     ///
     /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
-    /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
+    /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
     /// where those bugs are not an issue.
     ///
     /// This is an alias for [`std::fs::exists`](crate::fs::exists).
@@ -3180,6 +3181,7 @@ impl Path {
     /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
     /// ```
     ///
+    /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
     /// [`exists()`]: Self::exists
     #[stable(feature = "path_try_exists", since = "1.63.0")]
     #[inline]
diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs
index 73c25831872..c77c50fece1 100644
--- a/library/std/src/sys/net/connection/socket/wasip2.rs
+++ b/library/std/src/sys/net/connection/socket/wasip2.rs
@@ -140,7 +140,7 @@ impl Socket {
                 0 => {}
                 _ => {
                     // WASI poll does not return  POLLHUP or POLLERR in revents. Check if the
-                    // connnection actually succeeded and return ok only when the socket is
+                    // connection actually succeeded and return ok only when the socket is
                     // ready and no errors were found.
                     if let Some(e) = self.take_error()? {
                         return Err(e);
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index e47263348db..420481648a7 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -487,7 +487,7 @@ impl<T> OwnedProtocol<T> {
         let protocol: *mut T = Box::into_raw(Box::new(protocol));
         let mut handle: r_efi::efi::Handle = crate::ptr::null_mut();
 
-        // FIXME: Move into r-efi once extended_varargs_abi_support is stablized
+        // FIXME: Move into r-efi once extended_varargs_abi_support is stabilized
         let func: BootInstallMultipleProtocolInterfaces =
             unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) };
 
@@ -521,7 +521,7 @@ impl<T> Drop for OwnedProtocol<T> {
         // Do not deallocate a runtime protocol
         if let Some(bt) = boot_services() {
             let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
-            // FIXME: Move into r-efi once extended_varargs_abi_support is stablized
+            // FIXME: Move into r-efi once extended_varargs_abi_support is stabilized
             let func: BootUninstallMultipleProtocolInterfaces = unsafe {
                 crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces)
             };
@@ -645,7 +645,7 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result<BorrowedDeviceP
 }
 
 /// Helper for UEFI Protocols which are created and destroyed using
-/// [EFI_SERVICE_BINDING_PROTCOL](https://uefi.org/specs/UEFI/2.11/11_Protocols_UEFI_Driver_Model.html#efi-service-binding-protocol)
+/// [EFI_SERVICE_BINDING_PROTOCOL](https://uefi.org/specs/UEFI/2.11/11_Protocols_UEFI_Driver_Model.html#efi-service-binding-protocol)
 pub(crate) struct ServiceProtocol {
     service_guid: r_efi::efi::Guid,
     handle: NonNull<crate::ffi::c_void>,
diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs
index e90372805bb..da0982384b0 100644
--- a/library/std/src/sys/path/cygwin.rs
+++ b/library/std/src/sys/path/cygwin.rs
@@ -10,7 +10,7 @@ pub fn is_sep_byte(b: u8) -> bool {
     b == b'/' || b == b'\\'
 }
 
-/// Cygwin allways prefers `/` over `\`, and it always converts all `/` to `\`
+/// Cygwin always prefers `/` over `\`, and it always converts all `/` to `\`
 /// internally when calling Win32 APIs. Therefore, the server component of path
 /// `\\?\UNC\localhost/share` is `localhost/share` on Win32, but `localhost`
 /// on Cygwin.
diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs
index 18196fae28b..53e2f1da675 100644
--- a/library/std/src/sys/random/linux.rs
+++ b/library/std/src/sys/random/linux.rs
@@ -15,7 +15,7 @@
 //! bytes, while the non-blocking pool, once initialized using the blocking
 //! pool, uses a CPRNG to return an unlimited number of random bytes. With a
 //! strong enough CPRNG however, the entropy estimation didn't contribute that
-//! much towards security while being an excellent vector for DoS attacs. Thus,
+//! much towards security while being an excellent vector for DoS attacks. Thus,
 //! the blocking pool was removed in kernel version 5.6.[^2] That patch did not
 //! magically increase the quality of the non-blocking pool, however, so we can
 //! safely consider it strong enough even in older kernel versions and use it
@@ -30,7 +30,7 @@
 //! data the system has available at the time.
 //!
 //! So in conclusion, we always want the output of the non-blocking pool, but
-//! may need to wait until it is initalized. The default behavior of `getrandom`
+//! may need to wait until it is initialized. The default behavior of `getrandom`
 //! is to wait until the non-blocking pool is initialized and then draw from there,
 //! so if `getrandom` is available, we use its default to generate the bytes. For
 //! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that
diff --git a/library/std/src/sys/random/unsupported.rs b/library/std/src/sys/random/unsupported.rs
index d68ce4a9e87..894409b395a 100644
--- a/library/std/src/sys/random/unsupported.rs
+++ b/library/std/src/sys/random/unsupported.rs
@@ -6,7 +6,7 @@ pub fn fill_bytes(_: &mut [u8]) {
 
 pub fn hashmap_random_keys() -> (u64, u64) {
     // Use allocation addresses for a bit of randomness. This isn't
-    // particularily secure, but there isn't really an alternative.
+    // particularly secure, but there isn't really an alternative.
     let stack = 0u8;
     let heap = Box::new(0u8);
     let k1 = ptr::from_ref(&stack).addr() as u64;
diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs
index 98f471ad54b..c8a7bcf55c1 100644
--- a/library/std/src/thread/spawnhook.rs
+++ b/library/std/src/thread/spawnhook.rs
@@ -6,7 +6,7 @@ use crate::thread::Thread;
 crate::thread_local! {
     /// A thread local linked list of spawn hooks.
     ///
-    /// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads.
+    /// It is a linked list of Arcs, such that it can very cheaply be inherited by spawned threads.
     ///
     /// (That technically makes it a set of linked lists with shared tails, so a linked tree.)
     static SPAWN_HOOKS: Cell<SpawnHooks> = const { Cell::new(SpawnHooks { first: None }) };
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 03af35e809c..393426be087 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -95,10 +95,10 @@ use crate::sys_common::{FromInner, IntoInner};
 /// let now = Instant::now();
 /// let days_per_10_millennia = 365_2425;
 /// let solar_seconds_per_day = 60 * 60 * 24;
-/// let millenium_in_solar_seconds = 31_556_952_000;
-/// assert_eq!(millenium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10);
+/// let millennium_in_solar_seconds = 31_556_952_000;
+/// assert_eq!(millennium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10);
 ///
-/// let duration = Duration::new(millenium_in_solar_seconds, 0);
+/// let duration = Duration::new(millennium_in_solar_seconds, 0);
 /// println!("{:?}", now + duration);
 /// ```
 ///
diff --git a/library/std/tests/thread_local/tests.rs b/library/std/tests/thread_local/tests.rs
index e8278361d93..5df1a0e25ee 100644
--- a/library/std/tests/thread_local/tests.rs
+++ b/library/std/tests/thread_local/tests.rs
@@ -348,7 +348,7 @@ fn join_orders_after_tls_destructors() {
 //
 // The test won't currently work without target_thread_local, aka with slow tls.
 // The runtime tries very hard to drop last the TLS variable that keeps the information about the
-// current thread, by using several tricks like deffering the drop to a later round of TLS destruction.
+// current thread, by using several tricks like deferring the drop to a later round of TLS destruction.
 // However, this only seems to work with fast tls.
 //
 // With slow TLS, it seems that multiple libc implementations will just set the value to null the first
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 567416d079b..6c5f70b2f43 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -5,7 +5,7 @@ use crate::core::build_steps::compile::{
 };
 use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
 use crate::core::builder::{
-    self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description,
+    self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
 };
 use crate::core::config::TargetSelection;
 use crate::utils::build_stamp::{self, BuildStamp};
@@ -167,6 +167,10 @@ impl Step for Std {
         let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage));
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
+
+    fn metadata(&self) -> Option<StepMetadata> {
+        Some(StepMetadata::check("std", self.target))
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -258,6 +262,10 @@ impl Step for Rustc {
         let hostdir = builder.sysroot_target_libdir(compiler, compiler.host);
         add_to_sysroot(builder, &libdir, &hostdir, &stamp);
     }
+
+    fn metadata(&self) -> Option<StepMetadata> {
+        Some(StepMetadata::check("rustc", self.target))
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -315,6 +323,10 @@ impl Step for CodegenBackend {
 
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
+
+    fn metadata(&self) -> Option<StepMetadata> {
+        Some(StepMetadata::check(self.backend, self.target))
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -373,6 +385,10 @@ impl Step for RustAnalyzer {
         let _guard = builder.msg_check("rust-analyzer artifacts", target, None);
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
+
+    fn metadata(&self) -> Option<StepMetadata> {
+        Some(StepMetadata::check("rust-analyzer", self.target))
+    }
 }
 
 /// Compiletest is implicitly "checked" when it gets built in order to run tests,
@@ -432,6 +448,10 @@ impl Step for Compiletest {
         let _guard = builder.msg_check("compiletest artifacts", self.target, None);
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
+
+    fn metadata(&self) -> Option<StepMetadata> {
+        Some(StepMetadata::check("compiletest", self.target))
+    }
 }
 
 macro_rules! tool_check_step {
@@ -467,6 +487,10 @@ macro_rules! tool_check_step {
                 let Self { target } = self;
                 run_tool_check_step(builder, target, stringify!($name), $path);
             }
+
+            fn metadata(&self) -> Option<StepMetadata> {
+                Some(StepMetadata::check(stringify!($name), self.target))
+            }
         }
     }
 }
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index 882fcd08780..f67569d1486 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -181,7 +181,7 @@ fn rm_rf(path: &Path) {
             panic!("failed to get metadata for file {}: {}", path.display(), e);
         }
         Ok(metadata) => {
-            if metadata.file_type().is_file() || metadata.file_type().is_symlink() {
+            if !metadata.file_type().is_dir() {
                 do_op(path, "remove file", |p| match fs::remove_file(p) {
                     #[cfg(windows)]
                     Err(e)
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 84064150738..c3a3eddd161 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -306,11 +306,7 @@ impl Step for Std {
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
-        Some(
-            StepMetadata::build("std", self.target)
-                .built_by(self.compiler)
-                .stage(self.compiler.stage),
-        )
+        Some(StepMetadata::build("std", self.target).built_by(self.compiler))
     }
 }
 
@@ -1186,11 +1182,7 @@ impl Step for Rustc {
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
-        Some(
-            StepMetadata::build("rustc", self.target)
-                .built_by(self.build_compiler)
-                .stage(self.build_compiler.stage + 1),
-        )
+        Some(StepMetadata::build("rustc", self.target).built_by(self.build_compiler))
     }
 }
 
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 61268df7336..d487995e98a 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -346,6 +346,6 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
     // since last merge.
     //
     // NOTE: Because of the exit above, this is only reachable if formatting / format checking
-    // succeeded. So we are not commiting the version if formatting was not good.
+    // succeeded. So we are not committing the version if formatting was not good.
     update_rustfmt_version(build);
 }
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 01b181f55de..2d4d9e53598 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1108,7 +1108,9 @@ impl Step for Tidy {
         if builder.config.cmd.bless() {
             cmd.arg("--bless");
         }
-        if let Some(s) = builder.config.cmd.extra_checks() {
+        if let Some(s) =
+            builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref())
+        {
             cmd.arg(format!("--extra-checks={s}"));
         }
         let mut args = std::env::args_os();
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index a7220515ca0..ad3f8d89767 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1195,7 +1195,6 @@ macro_rules! tool_extended {
                 Some(
                     StepMetadata::build($tool_name, self.target)
                         .built_by(self.compiler.with_stage(self.compiler.stage.saturating_sub(1)))
-                        .stage(self.compiler.stage)
                 )
             }
         }
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 8e9e8b496de..b96a988cde3 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -153,6 +153,10 @@ impl StepMetadata {
         Self::new(name, target, Kind::Build)
     }
 
+    pub fn check(name: &'static str, target: TargetSelection) -> Self {
+        Self::new(name, target, Kind::Check)
+    }
+
     pub fn doc(name: &'static str, target: TargetSelection) -> Self {
         Self::new(name, target, Kind::Doc)
     }
@@ -178,6 +182,14 @@ impl StepMetadata {
         self.stage = Some(stage);
         self
     }
+
+    pub fn get_stage(&self) -> Option<u32> {
+        self.stage.or(self
+            .built_by
+            // For std, its stage corresponds to the stage of the compiler that builds it.
+            // For everything else, a stage N things gets built by a stage N-1 compiler.
+            .map(|compiler| if self.name == "std" { compiler.stage } else { compiler.stage + 1 }))
+    }
 }
 
 pub struct RunConfig<'a> {
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 8adf93ea528..1c5267cb75e 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -863,7 +863,7 @@ mod snapshot {
         insta::assert_snapshot!(
             ctx.config("build")
                 .path("opt-dist")
-                .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>");
+                .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>");
     }
 
     #[test]
@@ -880,7 +880,7 @@ mod snapshot {
             ctx.config("build")
                 .path("opt-dist")
                 .stage(1)
-                .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>");
+                .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>");
     }
 
     #[test]
@@ -890,7 +890,7 @@ mod snapshot {
             ctx.config("build")
                 .path("opt-dist")
                 .stage(2)
-                .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>");
+                .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>");
     }
 
     #[test]
@@ -984,8 +984,8 @@ mod snapshot {
             ctx
                 .config("dist")
                 .render_steps(), @r"
-        [build] rustc 0 <host> -> UnstableBookGen <host>
-        [build] rustc 0 <host> -> Rustbook <host>
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
@@ -993,14 +993,14 @@ mod snapshot {
         [build] rustdoc 1 <host>
         [doc] std 2 <host>
         [build] rustc 2 <host> -> std 2 <host>
-        [build] rustc 0 <host> -> LintDocs <host>
-        [build] rustc 0 <host> -> RustInstaller <host>
+        [build] rustc 0 <host> -> LintDocs 1 <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
         [dist] docs <host>
         [doc] std 2 <host>
         [dist] mingw <host>
-        [build] rustc 0 <host> -> GenerateCopyright <host>
+        [build] rustc 0 <host> -> GenerateCopyright 1 <host>
         [dist] rustc <host>
-        [dist] rustc 1 <host> -> std <host>
+        [dist] rustc 1 <host> -> std 1 <host>
         [dist] src <>
         "
         );
@@ -1014,25 +1014,25 @@ mod snapshot {
                 .config("dist")
                 .args(&["--set", "build.extended=true"])
                 .render_steps(), @r"
-        [build] rustc 0 <host> -> UnstableBookGen <host>
-        [build] rustc 0 <host> -> Rustbook <host>
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
-        [build] rustc 0 <host> -> WasmComponentLd <host>
+        [build] rustc 0 <host> -> WasmComponentLd 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
         [build] rustc 1 <host> -> rustc 2 <host>
-        [build] rustc 1 <host> -> WasmComponentLd <host>
+        [build] rustc 1 <host> -> WasmComponentLd 2 <host>
         [build] rustdoc 1 <host>
         [doc] std 2 <host>
         [build] rustc 2 <host> -> std 2 <host>
-        [build] rustc 0 <host> -> LintDocs <host>
-        [build] rustc 0 <host> -> RustInstaller <host>
+        [build] rustc 0 <host> -> LintDocs 1 <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
         [dist] docs <host>
         [doc] std 2 <host>
         [dist] mingw <host>
-        [build] rustc 0 <host> -> GenerateCopyright <host>
+        [build] rustc 0 <host> -> GenerateCopyright 1 <host>
         [dist] rustc <host>
-        [dist] rustc 1 <host> -> std <host>
+        [dist] rustc 1 <host> -> std 1 <host>
         [dist] src <>
         [build] rustc 0 <host> -> rustfmt 1 <host>
         [build] rustc 0 <host> -> cargo-fmt 1 <host>
@@ -1052,8 +1052,8 @@ mod snapshot {
                 .hosts(&[&host_target()])
                 .targets(&[&host_target(), TEST_TRIPLE_1])
                 .render_steps(), @r"
-        [build] rustc 0 <host> -> UnstableBookGen <host>
-        [build] rustc 0 <host> -> Rustbook <host>
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
@@ -1062,19 +1062,19 @@ mod snapshot {
         [doc] std 2 <host>
         [doc] std 2 <target1>
         [build] rustc 2 <host> -> std 2 <host>
-        [build] rustc 0 <host> -> LintDocs <host>
-        [build] rustc 0 <host> -> RustInstaller <host>
+        [build] rustc 0 <host> -> LintDocs 1 <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
         [dist] docs <host>
         [dist] docs <target1>
         [doc] std 2 <host>
         [doc] std 2 <target1>
         [dist] mingw <host>
         [dist] mingw <target1>
-        [build] rustc 0 <host> -> GenerateCopyright <host>
+        [build] rustc 0 <host> -> GenerateCopyright 1 <host>
         [dist] rustc <host>
-        [dist] rustc 1 <host> -> std <host>
+        [dist] rustc 1 <host> -> std 1 <host>
         [build] rustc 2 <host> -> std 2 <target1>
-        [dist] rustc 2 <host> -> std <target1>
+        [dist] rustc 2 <host> -> std 2 <target1>
         [dist] src <>
         "
         );
@@ -1089,8 +1089,8 @@ mod snapshot {
                 .hosts(&[&host_target(), TEST_TRIPLE_1])
                 .targets(&[&host_target()])
                 .render_steps(), @r"
-        [build] rustc 0 <host> -> UnstableBookGen <host>
-        [build] rustc 0 <host> -> Rustbook <host>
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
@@ -1098,20 +1098,20 @@ mod snapshot {
         [build] rustdoc 1 <host>
         [doc] std 2 <host>
         [build] rustc 2 <host> -> std 2 <host>
-        [build] rustc 0 <host> -> LintDocs <host>
+        [build] rustc 0 <host> -> LintDocs 1 <host>
         [build] rustc 1 <host> -> std 1 <target1>
         [build] rustc 2 <host> -> std 2 <target1>
-        [build] rustc 0 <host> -> RustInstaller <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
         [dist] docs <host>
         [doc] std 2 <host>
         [dist] mingw <host>
-        [build] rustc 0 <host> -> GenerateCopyright <host>
+        [build] rustc 0 <host> -> GenerateCopyright 1 <host>
         [dist] rustc <host>
         [build] llvm <target1>
         [build] rustc 1 <host> -> rustc 2 <target1>
         [build] rustdoc 1 <target1>
         [dist] rustc <target1>
-        [dist] rustc 1 <host> -> std <host>
+        [dist] rustc 1 <host> -> std 1 <host>
         [dist] src <>
         "
         );
@@ -1126,8 +1126,8 @@ mod snapshot {
                 .hosts(&[&host_target(), TEST_TRIPLE_1])
                 .targets(&[&host_target(), TEST_TRIPLE_1])
                 .render_steps(), @r"
-        [build] rustc 0 <host> -> UnstableBookGen <host>
-        [build] rustc 0 <host> -> Rustbook <host>
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
@@ -1136,24 +1136,24 @@ mod snapshot {
         [doc] std 2 <host>
         [doc] std 2 <target1>
         [build] rustc 2 <host> -> std 2 <host>
-        [build] rustc 0 <host> -> LintDocs <host>
+        [build] rustc 0 <host> -> LintDocs 1 <host>
         [build] rustc 1 <host> -> std 1 <target1>
         [build] rustc 2 <host> -> std 2 <target1>
-        [build] rustc 0 <host> -> RustInstaller <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
         [dist] docs <host>
         [dist] docs <target1>
         [doc] std 2 <host>
         [doc] std 2 <target1>
         [dist] mingw <host>
         [dist] mingw <target1>
-        [build] rustc 0 <host> -> GenerateCopyright <host>
+        [build] rustc 0 <host> -> GenerateCopyright 1 <host>
         [dist] rustc <host>
         [build] llvm <target1>
         [build] rustc 1 <host> -> rustc 2 <target1>
         [build] rustdoc 1 <target1>
         [dist] rustc <target1>
-        [dist] rustc 1 <host> -> std <host>
-        [dist] rustc 1 <host> -> std <target1>
+        [dist] rustc 1 <host> -> std 1 <host>
+        [dist] rustc 1 <host> -> std 1 <target1>
         [dist] src <>
         "
         );
@@ -1168,8 +1168,8 @@ mod snapshot {
                 .hosts(&[])
                 .targets(&[TEST_TRIPLE_1])
                 .render_steps(), @r"
-        [build] rustc 0 <host> -> UnstableBookGen <host>
-        [build] rustc 0 <host> -> Rustbook <host>
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
@@ -1177,12 +1177,12 @@ mod snapshot {
         [build] rustdoc 1 <host>
         [doc] std 2 <target1>
         [build] rustc 2 <host> -> std 2 <host>
-        [build] rustc 0 <host> -> RustInstaller <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
         [dist] docs <target1>
         [doc] std 2 <target1>
         [dist] mingw <target1>
         [build] rustc 2 <host> -> std 2 <target1>
-        [dist] rustc 2 <host> -> std <target1>
+        [dist] rustc 2 <host> -> std 2 <target1>
         ");
     }
 
@@ -1198,31 +1198,31 @@ mod snapshot {
                 .targets(&[TEST_TRIPLE_1])
                 .args(&["--set", "rust.channel=nightly", "--set", "build.extended=true"])
                 .render_steps(), @r"
-        [build] rustc 0 <host> -> UnstableBookGen <host>
-        [build] rustc 0 <host> -> Rustbook <host>
+        [build] rustc 0 <host> -> UnstableBookGen 1 <host>
+        [build] rustc 0 <host> -> Rustbook 1 <host>
         [build] llvm <host>
         [build] rustc 0 <host> -> rustc 1 <host>
-        [build] rustc 0 <host> -> WasmComponentLd <host>
+        [build] rustc 0 <host> -> WasmComponentLd 1 <host>
         [build] rustc 1 <host> -> std 1 <host>
         [build] rustc 1 <host> -> rustc 2 <host>
-        [build] rustc 1 <host> -> WasmComponentLd <host>
+        [build] rustc 1 <host> -> WasmComponentLd 2 <host>
         [build] rustdoc 1 <host>
         [doc] std 2 <target1>
         [build] rustc 2 <host> -> std 2 <host>
         [build] rustc 1 <host> -> std 1 <target1>
         [build] rustc 2 <host> -> std 2 <target1>
-        [build] rustc 0 <host> -> LintDocs <host>
-        [build] rustc 0 <host> -> RustInstaller <host>
+        [build] rustc 0 <host> -> LintDocs 1 <host>
+        [build] rustc 0 <host> -> RustInstaller 1 <host>
         [dist] docs <target1>
         [doc] std 2 <target1>
         [dist] mingw <target1>
         [build] llvm <target1>
         [build] rustc 1 <host> -> rustc 2 <target1>
-        [build] rustc 1 <host> -> WasmComponentLd <target1>
+        [build] rustc 1 <host> -> WasmComponentLd 2 <target1>
         [build] rustdoc 1 <target1>
-        [build] rustc 0 <host> -> GenerateCopyright <host>
+        [build] rustc 0 <host> -> GenerateCopyright 1 <host>
         [dist] rustc <target1>
-        [dist] rustc 1 <host> -> std <target1>
+        [dist] rustc 1 <host> -> std 1 <target1>
         [dist] src <>
         [build] rustc 0 <host> -> rustfmt 1 <target1>
         [build] rustc 0 <host> -> cargo-fmt 1 <target1>
@@ -1234,6 +1234,289 @@ mod snapshot {
     }
 
     #[test]
+    fn check_compiler_no_explicit_stage() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("compiler")
+                .render_steps(), @r"
+        [check] std <host>
+        [build] llvm <host>
+        [check] rustc <host>
+        [check] cranelift <host>
+        [check] gcc <host>
+        ");
+
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("rustc")
+                .render_steps(), @r"
+        [check] std <host>
+        [build] llvm <host>
+        [check] rustc <host>
+        ");
+    }
+
+    #[test]
+    fn check_compiler_stage_0() {
+        let ctx = TestCtx::new();
+        ctx.config("check").path("compiler").stage(0).run();
+    }
+
+    #[test]
+    fn check_compiler_stage_1() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("compiler")
+                .stage(1)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [check] rustc <host>
+        [check] cranelift <host>
+        [check] gcc <host>
+        ");
+    }
+
+    #[test]
+    fn check_compiler_stage_2() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("compiler")
+                .stage(2)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 2 <host> -> std 2 <host>
+        [check] rustc <host>
+        [check] cranelift <host>
+        [check] gcc <host>
+        ");
+    }
+
+    #[test]
+    fn check_cross_compile() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .stage(2)
+                .targets(&[TEST_TRIPLE_1])
+                .hosts(&[TEST_TRIPLE_1])
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 2 <host> -> std 2 <host>
+        [build] rustc 1 <host> -> std 1 <target1>
+        [build] rustc 2 <host> -> std 2 <target1>
+        [check] rustc <target1>
+        [check] Rustdoc <target1>
+        [check] cranelift <target1>
+        [check] gcc <target1>
+        [check] Clippy <target1>
+        [check] Miri <target1>
+        [check] CargoMiri <target1>
+        [check] MiroptTestTools <target1>
+        [check] Rustfmt <target1>
+        [check] rust-analyzer <target1>
+        [check] TestFloatParse <target1>
+        [check] FeaturesStatusDump <target1>
+        [check] std <target1>
+        ");
+    }
+
+    #[test]
+    fn check_library_no_explicit_stage() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("library")
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [check] std <host>
+        ");
+    }
+
+    #[test]
+    fn check_library_stage_0() {
+        let ctx = TestCtx::new();
+        ctx.config("check").path("library").stage(0).run();
+    }
+
+    #[test]
+    fn check_library_stage_1() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("library")
+                .stage(1)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [check] std <host>
+        ");
+    }
+
+    #[test]
+    fn check_library_stage_2() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("library")
+                .stage(2)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [check] std <host>
+        ");
+    }
+
+    #[test]
+    fn check_library_cross_compile() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .paths(&["core", "alloc", "std"])
+                .targets(&[TEST_TRIPLE_1, TEST_TRIPLE_2])
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [check] std <target1>
+        [check] std <target2>
+        ");
+    }
+
+    #[test]
+    fn check_miri_no_explicit_stage() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("miri")
+                .render_steps(), @r"
+        [check] std <host>
+        [build] llvm <host>
+        [check] rustc <host>
+        [check] Miri <host>
+        ");
+    }
+
+    #[test]
+    fn check_miri_stage_0() {
+        let ctx = TestCtx::new();
+        ctx.config("check").path("miri").stage(0).run();
+    }
+
+    #[test]
+    fn check_miri_stage_1() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("miri")
+                .stage(1)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [check] rustc <host>
+        [check] Miri <host>
+        ");
+    }
+
+    #[test]
+    fn check_miri_stage_2() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("miri")
+                .stage(2)
+                .render_steps(), @r"
+        [build] llvm <host>
+        [build] rustc 0 <host> -> rustc 1 <host>
+        [build] rustc 1 <host> -> std 1 <host>
+        [build] rustc 1 <host> -> rustc 2 <host>
+        [build] rustc 2 <host> -> std 2 <host>
+        [check] rustc <host>
+        [check] Miri <host>
+        ");
+    }
+
+    #[test]
+    fn check_compiletest() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("compiletest")
+                .render_steps(), @"[check] compiletest <host>");
+    }
+
+    #[test]
+    fn check_compiletest_stage1_libtest() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("compiletest")
+                .args(&["--set", "build.compiletest-use-stage0-libtest=false"])
+                .render_steps(), @r"
+        [check] std <host>
+        [build] llvm <host>
+        [check] rustc <host>
+        [check] compiletest <host>
+        ");
+    }
+
+    #[test]
+    fn check_codegen() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("rustc_codegen_cranelift")
+                .render_steps(), @r"
+        [check] std <host>
+        [build] llvm <host>
+        [check] rustc <host>
+        [check] cranelift <host>
+        [check] gcc <host>
+        ");
+    }
+
+    #[test]
+    fn check_rust_analyzer() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("rust-analyzer")
+                .render_steps(), @r"
+        [check] std <host>
+        [build] llvm <host>
+        [check] rustc <host>
+        [check] rust-analyzer <host>
+        ");
+    }
+
+    #[test]
+    fn check_bootstrap_tool() {
+        let ctx = TestCtx::new();
+        insta::assert_snapshot!(
+            ctx.config("check")
+                .path("run-make-support")
+                .render_steps(), @r"
+        [check] std <host>
+        [build] llvm <host>
+        [check] rustc <host>
+        [check] RunMakeSupport <host>
+        ");
+    }
+
+    #[test]
     fn test_exclude() {
         let ctx = TestCtx::new();
         let steps = ctx.config("test").args(&["--skip", "src/tools/tidy"]).get_steps();
@@ -1384,7 +1667,7 @@ fn render_metadata(metadata: &StepMetadata) -> String {
     if let Some(compiler) = metadata.built_by {
         write!(record, "{} -> ", render_compiler(compiler));
     }
-    let stage = if let Some(stage) = metadata.stage { format!("{stage} ") } else { "".to_string() };
+    let stage = metadata.get_stage().map(|stage| format!("{stage} ")).unwrap_or_default();
     write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target));
     record
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 0cdfbbdaf75..49b3fec4c35 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -297,7 +297,8 @@ pub struct Config {
 
     /// Whether to use the precompiled stage0 libtest with compiletest.
     pub compiletest_use_stage0_libtest: bool,
-
+    /// Default value for `--extra-checks`
+    pub tidy_extra_checks: Option<String>,
     pub is_running_on_ci: bool,
 
     /// Cache for determining path modifications
@@ -744,6 +745,7 @@ impl Config {
             jobs,
             compiletest_diff_tool,
             compiletest_use_stage0_libtest,
+            tidy_extra_checks,
             mut ccache,
             exclude,
         } = toml.build.unwrap_or_default();
@@ -1010,6 +1012,7 @@ impl Config {
             optimized_compiler_builtins.unwrap_or(config.channel != "dev");
         config.compiletest_diff_tool = compiletest_diff_tool;
         config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true);
+        config.tidy_extra_checks = tidy_extra_checks;
 
         let download_rustc = config.download_rustc_commit.is_some();
         config.explicit_stage_from_cli = flags_stage.is_some();
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index bb21d033458..79275db6486 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -382,7 +382,7 @@ pub enum Subcommand {
         bless: bool,
         #[arg(long)]
         /// comma-separated list of other files types to check (accepts py, py:lint,
-        /// py:fmt, shell)
+        /// py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)
         extra_checks: Option<String>,
         #[arg(long)]
         /// rerun tests even if the inputs are unchanged
diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs
index 98e1194de72..4d29691f38b 100644
--- a/src/bootstrap/src/core/config/toml/build.rs
+++ b/src/bootstrap/src/core/config/toml/build.rs
@@ -69,6 +69,7 @@ define_config! {
         jobs: Option<u32> = "jobs",
         compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
         compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
+        tidy_extra_checks: Option<String> = "tidy-extra-checks",
         ccache: Option<StringOrBool> = "ccache",
         exclude: Option<Vec<PathBuf>> = "exclude",
     }
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
index 642f2f2271d..ac5eaea3bcb 100644
--- a/src/bootstrap/src/core/config/toml/rust.rs
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -393,6 +393,27 @@ pub fn check_incompatible_options_for_ci_rustc(
     Ok(())
 }
 
+pub(crate) const VALID_CODEGEN_BACKENDS: &[&str] = &["llvm", "cranelift", "gcc"];
+
+pub(crate) fn validate_codegen_backends(backends: Vec<String>, section: &str) -> Vec<String> {
+    for backend in &backends {
+        if let Some(stripped) = backend.strip_prefix(CODEGEN_BACKEND_PREFIX) {
+            panic!(
+                "Invalid value '{backend}' for '{section}.codegen-backends'. \
+                Codegen backends are defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
+                Please, use '{stripped}' instead."
+            )
+        }
+        if !VALID_CODEGEN_BACKENDS.contains(&backend.as_str()) {
+            println!(
+                "HELP: '{backend}' for '{section}.codegen-backends' might fail. \
+                List of known good values: {VALID_CODEGEN_BACKENDS:?}"
+            );
+        }
+    }
+    backends
+}
+
 impl Config {
     pub fn apply_rust_config(
         &mut self,
@@ -571,24 +592,10 @@ impl Config {
             set(&mut self.ehcont_guard, ehcont_guard);
             self.llvm_libunwind_default =
                 llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
-
-            if let Some(ref backends) = codegen_backends {
-                let available_backends = ["llvm", "cranelift", "gcc"];
-
-                self.rust_codegen_backends = backends.iter().map(|s| {
-                    if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
-                        if available_backends.contains(&backend) {
-                            panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'.");
-                        } else {
-                            println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
-                                Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
-                                In this case, it would be referred to as '{backend}'.");
-                        }
-                    }
-
-                    s.clone()
-                }).collect();
-            }
+            set(
+                &mut self.rust_codegen_backends,
+                codegen_backends.map(|backends| validate_codegen_backends(backends, "rust")),
+            );
 
             self.rust_codegen_units = codegen_units.map(threads_from_config);
             self.rust_codegen_units_std = codegen_units_std.map(threads_from_config);
diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs
index b9f6780ca3f..337276948b3 100644
--- a/src/bootstrap/src/core/config/toml/target.rs
+++ b/src/bootstrap/src/core/config/toml/target.rs
@@ -16,7 +16,7 @@ use std::collections::HashMap;
 
 use serde::{Deserialize, Deserializer};
 
-use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
+use crate::core::config::toml::rust::validate_codegen_backends;
 use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool};
 use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit};
 
@@ -142,23 +142,9 @@ impl Config {
                 target.rpath = cfg.rpath;
                 target.optimized_compiler_builtins = cfg.optimized_compiler_builtins;
                 target.jemalloc = cfg.jemalloc;
-
-                if let Some(ref backends) = cfg.codegen_backends {
-                    let available_backends = ["llvm", "cranelift", "gcc"];
-
-                    target.codegen_backends = Some(backends.iter().map(|s| {
-                        if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
-                            if available_backends.contains(&backend) {
-                                panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
-                            } else {
-                                println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
-                                    Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
-                                    In this case, it would be referred to as '{backend}'.");
-                            }
-                        }
-
-                        s.clone()
-                    }).collect());
+                if let Some(backends) = cfg.codegen_backends {
+                    target.codegen_backends =
+                        Some(validate_codegen_backends(backends, &format!("target.{triple}")))
                 }
 
                 target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| {
diff --git a/src/bootstrap/src/utils/cache/tests.rs b/src/bootstrap/src/utils/cache/tests.rs
index 8562a35b3e0..fd0a7cccd60 100644
--- a/src/bootstrap/src/utils/cache/tests.rs
+++ b/src/bootstrap/src/utils/cache/tests.rs
@@ -1,12 +1,13 @@
 use std::path::PathBuf;
 
-use crate::utils::cache::{INTERNER, Internable, TyIntern};
+use crate::utils::cache::{INTERNER, Internable, Interner, TyIntern};
 
 #[test]
 fn test_string_interning() {
-    let s1 = INTERNER.intern_str("Hello");
-    let s2 = INTERNER.intern_str("Hello");
-    let s3 = INTERNER.intern_str("world");
+    let interner = Interner::default();
+    let s1 = interner.intern_str("Hello");
+    let s2 = interner.intern_str("Hello");
+    let s3 = interner.intern_str("world");
 
     assert_eq!(s1, s2, "Same strings should be interned to the same instance");
     assert_ne!(s1, s3, "Different strings should have different interned values");
@@ -14,6 +15,8 @@ fn test_string_interning() {
 
 #[test]
 fn test_interned_equality() {
+    // Because we compare with &str, and the Deref impl accesses the global
+    // INTERNER variable, we cannot use a local Interner variable here.
     let s1 = INTERNER.intern_str("test");
     let s2 = INTERNER.intern_str("test");
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index f873c62588b..68312a503ee 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -149,7 +149,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
     ChangeInfo {
         change_id: 121976,
         severity: ChangeSeverity::Info,
-        summary: "A new `boostrap-cache-path` option has been introduced which can be utilized to modify the cache path for bootstrap.",
+        summary: "A new `bootstrap-cache-path` option has been introduced which can be utilized to modify the cache path for bootstrap.",
     },
     ChangeInfo {
         change_id: 122108,
@@ -404,7 +404,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
     ChangeInfo {
         change_id: 140438,
         severity: ChangeSeverity::Info,
-        summary: "Added a new option `rust.debug-assertions-tools` to control debug asssertions for tools.",
+        summary: "Added a new option `rust.debug-assertions-tools` to control debug assertions for tools.",
     },
     ChangeInfo {
         change_id: 140732,
@@ -441,4 +441,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "`llvm.lld` is no longer enabled by default for the dist profile.",
     },
+    ChangeInfo {
+        change_id: 143251,
+        severity: ChangeSeverity::Info,
+        summary: "Added new option `build.tidy-extra-checks` to specify a default value for the --extra-checks cli flag.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs
index b61fa3bb8d6..21c7fc89d7d 100644
--- a/src/bootstrap/src/utils/proc_macro_deps.rs
+++ b/src/bootstrap/src/utils/proc_macro_deps.rs
@@ -30,7 +30,6 @@ pub static CRATES: &[&str] = &[
     "memchr",
     "minimal-lexical",
     "nom",
-    "once_cell",
     "pest",
     "pest_generator",
     "pest_meta",
diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs
index 81e002edb15..410274227e4 100644
--- a/src/ci/citool/src/jobs.rs
+++ b/src/ci/citool/src/jobs.rs
@@ -13,7 +13,7 @@ use crate::utils::load_env_var;
 #[derive(serde::Deserialize, Debug, Clone)]
 #[serde(deny_unknown_fields)]
 pub struct Job {
-    /// Name of the job, e.g. mingw-check-1
+    /// Name of the job, e.g. pr-check-1
     pub name: String,
     /// GitHub runner on which the job should be executed
     pub os: String,
@@ -66,6 +66,8 @@ pub struct JobDatabase {
     pub try_jobs: Vec<Job>,
     #[serde(rename = "auto")]
     pub auto_jobs: Vec<Job>,
+    #[serde(rename = "optional")]
+    pub optional_jobs: Vec<Job>,
 
     /// Shared environments for the individual run types.
     envs: JobEnvironments,
@@ -75,9 +77,10 @@ impl JobDatabase {
     /// Find `auto` jobs that correspond to the passed `pattern`.
     /// Patterns are matched using the glob syntax.
     /// For example `dist-*` matches all jobs starting with `dist-`.
-    fn find_auto_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> {
+    fn find_auto_or_optional_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> {
         self.auto_jobs
             .iter()
+            .chain(self.optional_jobs.iter())
             .filter(|j| glob_match::glob_match(pattern, &j.name))
             .cloned()
             .collect()
@@ -181,7 +184,7 @@ fn calculate_jobs(
                 let mut jobs: Vec<Job> = vec![];
                 let mut unknown_patterns = vec![];
                 for pattern in patterns {
-                    let matched_jobs = db.find_auto_jobs_by_pattern(pattern);
+                    let matched_jobs = db.find_auto_or_optional_jobs_by_pattern(pattern);
                     if matched_jobs.is_empty() {
                         unknown_patterns.push(pattern.clone());
                     } else {
diff --git a/src/ci/citool/src/jobs/tests.rs b/src/ci/citool/src/jobs/tests.rs
index ed5444d4333..63ac508b632 100644
--- a/src/ci/citool/src/jobs/tests.rs
+++ b/src/ci/citool/src/jobs/tests.rs
@@ -46,6 +46,13 @@ auto:
     - name: test-msvc-i686-2
       os: ubuntu
       env: {}
+optional:
+    - name: optional-job-1
+      os: ubuntu
+      env: {}
+    - name: optional-dist-x86_64
+      os: ubuntu
+      env: {}
 "#,
     )
     .unwrap();
@@ -57,12 +64,18 @@ auto:
         "*i686*",
         &["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"],
     );
+    // Test that optional jobs are found
+    check_pattern(&db, "optional-*", &["optional-job-1", "optional-dist-x86_64"]);
+    check_pattern(&db, "*optional*", &["optional-job-1", "optional-dist-x86_64"]);
 }
 
 #[track_caller]
 fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) {
-    let jobs =
-        db.find_auto_jobs_by_pattern(pattern).into_iter().map(|j| j.name).collect::<Vec<_>>();
+    let jobs = db
+        .find_auto_or_optional_jobs_by_pattern(pattern)
+        .into_iter()
+        .map(|j| j.name)
+        .collect::<Vec<_>>();
 
     assert_eq!(jobs, expected);
 }
@@ -116,8 +129,13 @@ fn validate_jobs() {
         load_job_db(&db_str).expect("Failed to load job database")
     };
 
-    let all_jobs =
-        db.pr_jobs.iter().chain(db.try_jobs.iter()).chain(db.auto_jobs.iter()).collect::<Vec<_>>();
+    let all_jobs = db
+        .pr_jobs
+        .iter()
+        .chain(db.try_jobs.iter())
+        .chain(db.auto_jobs.iter())
+        .chain(db.optional_jobs.iter())
+        .collect::<Vec<_>>();
 
     let errors: Vec<anyhow::Error> =
         all_jobs.into_iter().filter_map(|job| validate_codebuild_image(job).err()).collect();
diff --git a/src/ci/citool/tests/jobs.rs b/src/ci/citool/tests/jobs.rs
index 83f2fc0ed1f..dbaf13d4f42 100644
--- a/src/ci/citool/tests/jobs.rs
+++ b/src/ci/citool/tests/jobs.rs
@@ -40,7 +40,7 @@ try-job: dist-i686-msvc"#,
 fn pr_jobs() {
     let stdout = get_matrix("pull_request", "commit", "refs/heads/pr/1234");
     insta::assert_snapshot!(stdout, @r#"
-    jobs=[{"name":"mingw-check-1","full_name":"PR - mingw-check-1","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-2","full_name":"PR - mingw-check-2","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-tidy","full_name":"PR - mingw-check-tidy","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"continue_on_error":true,"free_disk":true,"doc_url":"https://foo.bar"}]
+    jobs=[{"name":"pr-check-1","full_name":"PR - pr-check-1","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"pr-check-2","full_name":"PR - pr-check-2","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"tidy","full_name":"PR - tidy","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"continue_on_error":true,"free_disk":true,"doc_url":"https://foo.bar"}]
     run_type=pr
     "#);
 }
diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml
index d262da11102..d82b3e7648e 100644
--- a/src/ci/citool/tests/test-jobs.yml
+++ b/src/ci/citool/tests/test-jobs.yml
@@ -64,11 +64,11 @@ envs:
 # These jobs automatically inherit envs.pr, to avoid repeating
 # it in each job definition.
 pr:
-  - name: mingw-check-1
+  - name: pr-check-1
     <<: *job-linux-4c
-  - name: mingw-check-2
+  - name: pr-check-2
     <<: *job-linux-4c
-  - name: mingw-check-tidy
+  - name: tidy
     continue_on_error: true
     doc_url: https://foo.bar
     <<: *job-linux-4c
@@ -139,3 +139,8 @@ auto:
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows
+
+# Jobs that only run when explicitly invoked via `@bors try`.
+optional:
+  - name: test-optional-job
+    <<: *job-linux-4c
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
index d5027589e0b..e6133fce83e 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
@@ -26,6 +26,5 @@ ENV RUST_CONFIGURE_ARGS \
  --enable-sanitizers \
  --enable-profiler \
  --enable-compiler-docs
-# FIXME: Skipping cargo panic_abort_doc_tests due to https://github.com/rust-lang/rust/issues/123733
 ENV SCRIPT python3 ../x.py --stage 2 test && \
-  python3 ../x.py --stage 2 test src/tools/cargo --test-args \"--skip panic_abort_doc_tests\"
+  python3 ../x.py --stage 2 test src/tools/cargo
diff --git a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile
deleted file mode 100644
index c46a2471e75..00000000000
--- a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile
+++ /dev/null
@@ -1,58 +0,0 @@
-FROM ubuntu:22.04
-
-ARG DEBIAN_FRONTEND=noninteractive
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3 \
-  python3-pip \
-  python3-pkg-resources \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils \
-  libssl-dev \
-  pkg-config \
-  mingw-w64 \
-  && rm -rf /var/lib/apt/lists/*
-
-ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3"
-
-COPY scripts/nodejs.sh /scripts/
-RUN sh /scripts/nodejs.sh /node
-ENV PATH="/node/bin:${PATH}"
-
-# Install es-check
-# Pin its version to prevent unrelated CI failures due to future es-check versions.
-RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-COPY host-x86_64/mingw-check-1/reuse-requirements.txt /tmp/
-RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt
-
-COPY host-x86_64/mingw-check-1/check-default-config-profiles.sh /scripts/
-COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/
-
-# Check library crates on all tier 1 targets.
-# We disable optimized compiler built-ins because that requires a C toolchain for the target.
-# We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs.
-ENV SCRIPT \
-           /scripts/check-default-config-profiles.sh && \
-           python3 ../x.py build --stage 1 src/tools/build-manifest && \
-           python3 ../x.py test --stage 0 src/tools/compiletest && \
-           python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
-           python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
-           python3 ../x.py check --stage 1 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
-           /scripts/validate-toolstate.sh && \
-           reuse --include-submodules lint && \
-           python3 ../x.py test collect-license-metadata && \
-           # Runs checks to ensure that there are no issues in our JS code.
-           es-check es2019 ../src/librustdoc/html/static/js/*.js && \
-           tsc --project ../src/librustdoc/html/static/js/tsconfig.json
diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
new file mode 100644
index 00000000000..7a8056b70dc
--- /dev/null
+++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
@@ -0,0 +1,58 @@
+FROM ubuntu:22.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python3 \
+  python3-pip \
+  python3-pkg-resources \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  libssl-dev \
+  pkg-config \
+  mingw-w64 \
+  && rm -rf /var/lib/apt/lists/*
+
+ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3"
+
+COPY scripts/nodejs.sh /scripts/
+RUN sh /scripts/nodejs.sh /node
+ENV PATH="/node/bin:${PATH}"
+
+# Install es-check
+# Pin its version to prevent unrelated CI failures due to future es-check versions.
+RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+COPY host-x86_64/pr-check-1/reuse-requirements.txt /tmp/
+RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt
+
+COPY host-x86_64/pr-check-1/check-default-config-profiles.sh /scripts/
+COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/
+
+# Check library crates on all tier 1 targets.
+# We disable optimized compiler built-ins because that requires a C toolchain for the target.
+# We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs.
+ENV SCRIPT \
+  /scripts/check-default-config-profiles.sh && \
+  python3 ../x.py build --stage 1 src/tools/build-manifest && \
+  python3 ../x.py test --stage 0 src/tools/compiletest && \
+  python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
+  python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
+  python3 ../x.py check --stage 1 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
+  /scripts/validate-toolstate.sh && \
+  reuse --include-submodules lint && \
+  python3 ../x.py test collect-license-metadata && \
+  # Runs checks to ensure that there are no issues in our JS code.
+  es-check es2019 ../src/librustdoc/html/static/js/*.js && \
+  tsc --project ../src/librustdoc/html/static/js/tsconfig.json
diff --git a/src/ci/docker/host-x86_64/mingw-check-1/check-default-config-profiles.sh b/src/ci/docker/host-x86_64/pr-check-1/check-default-config-profiles.sh
index 0c85d4b449d..0c85d4b449d 100755
--- a/src/ci/docker/host-x86_64/mingw-check-1/check-default-config-profiles.sh
+++ b/src/ci/docker/host-x86_64/pr-check-1/check-default-config-profiles.sh
diff --git a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.in b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.in
index d7c2d3fde5b..d7c2d3fde5b 100644
--- a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.in
+++ b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.in
diff --git a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.txt b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.txt
index 8784e18864b..8784e18864b 100644
--- a/src/ci/docker/host-x86_64/mingw-check-1/reuse-requirements.txt
+++ b/src/ci/docker/host-x86_64/pr-check-1/reuse-requirements.txt
diff --git a/src/ci/docker/host-x86_64/mingw-check-1/validate-toolstate.sh b/src/ci/docker/host-x86_64/pr-check-1/validate-toolstate.sh
index a5691da8cda..a5691da8cda 100755
--- a/src/ci/docker/host-x86_64/mingw-check-1/validate-toolstate.sh
+++ b/src/ci/docker/host-x86_64/pr-check-1/validate-toolstate.sh
diff --git a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
index ce18a181d31..ce18a181d31 100644
--- a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile
index 62cd8a31212..dbb950cbe0c 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/tidy/Dockerfile
@@ -1,5 +1,5 @@
 # We use the ghcr base image because ghcr doesn't have a rate limit
-# and the mingw-check-tidy job doesn't cache docker images in CI.
+# and the tidy job doesn't cache docker images in CI.
 FROM ghcr.io/rust-lang/ubuntu:22.04
 
 ARG DEBIAN_FRONTEND=noninteractive
@@ -29,20 +29,20 @@ RUN sh /scripts/nodejs.sh /node
 ENV PATH="/node/bin:${PATH}"
 
 # Install eslint
-COPY host-x86_64/mingw-check-tidy/eslint.version /tmp/
+COPY host-x86_64/tidy/eslint.version /tmp/
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY host-x86_64/mingw-check-1/reuse-requirements.txt /tmp/
+COPY host-x86_64/pr-check-1/reuse-requirements.txt /tmp/
 RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt \
-    && pip3 install virtualenv
+  && pip3 install virtualenv
 
-COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/
+COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/
 
 RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)'
 
 # NOTE: intentionally uses python2 for x.py so we can test it still works.
 # validate-toolstate only runs in our CI, so it's ok for it to only support python3.
 ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \
-    src/tools/tidy tidyselftest --extra-checks=py,cpp
+  src/tools/tidy tidyselftest --extra-checks=py,cpp
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/eslint.version b/src/ci/docker/host-x86_64/tidy/eslint.version
index 1acea15afd6..1acea15afd6 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/eslint.version
+++ b/src/ci/docker/host-x86_64/tidy/eslint.version
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index f8d54d44557..b9f8e558df4 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.20.7
\ No newline at end of file
+0.21.1
\ No newline at end of file
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 3aa435003d3..01993ad28aa 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -122,11 +122,11 @@ jobs:
 # These jobs automatically inherit envs.pr, to avoid repeating
 # it in each job definition.
 pr:
-  - name: mingw-check-1
+  - name: pr-check-1
     <<: *job-linux-4c
-  - name: mingw-check-2
+  - name: pr-check-2
     <<: *job-linux-4c
-  - name: mingw-check-tidy
+  - name: tidy
     continue_on_error: true
     free_disk: false
     env:
@@ -160,6 +160,17 @@ pr:
 try:
   - <<: *job-dist-x86_64-linux
 
+# Jobs that only run when explicitly invoked in one of the following ways:
+# - comment `@bors2 try jobs=<job-name>`
+# - `try-job: <job-name>` in the PR description and comment `@bors try` or `@bors2 try`.
+optional:
+  # This job is used just to test optional jobs.
+  # It will be replaced by tier 2 and tier 3 jobs in the future.
+  - name: optional-mingw-check-1
+    env:
+      IMAGE: mingw-check-1
+    <<: *job-linux-4c
+
 # Main CI jobs that have to be green to merge a commit into master
 # These jobs automatically inherit envs.auto, to avoid repeating
 # it in each job definition.
@@ -312,13 +323,13 @@ auto:
         /scripts/stage_2_test_set2.sh
     <<: *job-linux-4c
 
-  - name: mingw-check-1
+  - name: pr-check-1
     <<: *job-linux-4c
 
-  - name: mingw-check-2
+  - name: pr-check-2
     <<: *job-linux-4c
 
-  - name: mingw-check-tidy
+  - name: tidy
     free_disk: false
     <<: *job-linux-4c
 
diff --git a/src/doc/rustc-dev-guide/src/solve/opaque-types.md b/src/doc/rustc-dev-guide/src/solve/opaque-types.md
index 6898ef3aa78..8880962d621 100644
--- a/src/doc/rustc-dev-guide/src/solve/opaque-types.md
+++ b/src/doc/rustc-dev-guide/src/solve/opaque-types.md
@@ -56,7 +56,7 @@ Finally, we check whether the item bounds of the opaque hold for the expected ty
 [source][item-bounds-ck].
 
 [norm]: https://github.com/rust-lang/rust/blob/384d26fc7e3bdd7687cc17b2662b091f6017ec2a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs#L13
-[coherence-example]: https://github.com/rust-lang/rust/blob/master/tests/ui/type-alias-impl-trait/coherence_different_hidden_ty.rs
+[coherence-example]: https://github.com/rust-lang/rust/blob/master/tests/ui/type-alias-impl-trait/coherence/coherence_different_hidden_ty.rs
 [placeholder-ck]: https://github.com/rust-lang/rust/blob/384d26fc7e3bdd7687cc17b2662b091f6017ec2a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs#L33
 [check-storage]: https://github.com/rust-lang/rust/blob/384d26fc7e3bdd7687cc17b2662b091f6017ec2a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs#L51-L52
 [eq-prev]: https://github.com/rust-lang/rust/blob/384d26fc7e3bdd7687cc17b2662b091f6017ec2a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs#L51-L59
diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md
index 96e4edc17a5..750e4fa1a0f 100644
--- a/src/doc/rustc-dev-guide/src/tests/ci.md
+++ b/src/doc/rustc-dev-guide/src/tests/ci.md
@@ -66,8 +66,8 @@ kinds of builds (sets of jobs).
 ### Pull Request builds
 
 After each push to a pull request, a set of `pr` jobs are executed. Currently,
-these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `mingw-check-1`, `mingw-check-2`
-and `mingw-check-tidy` jobs, all running on Linux. These execute a relatively short
+these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `pr-check-1`, `pr-check-2`
+and `tidy` jobs, all running on Linux. These execute a relatively short
 (~40 minutes) and lightweight test suite that should catch common issues. More
 specifically, they run a set of lints, they try to perform a cross-compile check
 build to Windows mingw (without producing any artifacts) and they test the
@@ -148,6 +148,13 @@ for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try b
 glob patterns, you might want to wrap them in backticks (`` ` ``) to avoid GitHub rendering
 the pattern as Markdown.
 
+The job pattern needs to match one or more jobs defined in the `auto` or `optional` sections
+of [`jobs.yml`]:
+
+- `auto` jobs are executed before a commit is merged into the `master` branch.
+- `optional` jobs are executed only when explicitly requested via a try build.
+  They are typically used for tier 2 and tier 3 targets.
+
 > **Using `try-job` PR description directives**
 >
 > 1. Identify which set of try-jobs you would like to exercise. You can
diff --git a/src/doc/rustc-dev-guide/src/tests/minicore.md b/src/doc/rustc-dev-guide/src/tests/minicore.md
index def9aaf8733..23b77279011 100644
--- a/src/doc/rustc-dev-guide/src/tests/minicore.md
+++ b/src/doc/rustc-dev-guide/src/tests/minicore.md
@@ -39,6 +39,12 @@ If you find a `core` item to be missing from the [`minicore`] stub, consider
 adding it to the test auxiliary if it's likely to be used or is already needed
 by more than one test.
 
+## Staying in sync with `core`
+
+The `minicore` items must be kept up to date with `core`. For consistent
+diagnostic output between using `core` and `minicore`, any `diagnostic`
+attributes (e.g. `on_unimplemented`) should be replicated exactly in `minicore`.
+
 ## Example codegen test that uses `minicore`
 
 ```rust,no_run
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 201a5503079..9fe4c218121 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -130,7 +130,7 @@
     - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
     - [x86_64-pc-cygwin](platform-support/x86_64-pc-cygwin.md)
-    - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md)
+    - [x86_64-unknown-linux-none](platform-support/x86_64-unknown-linux-none.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
     - [xtensa-\*-none-elf](platform-support/xtensa.md)
     - [\*-nuttx-\*](platform-support/nuttx.md)
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 64734d5bcaa..e982cde634f 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -293,7 +293,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand doc" -l skip-std-check-if-no-d
 complete -c x.py -n "__fish_x.py_using_subcommand doc" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l compiletest-rustc-args -d 'extra options to pass the compiler when running compiletest tests' -r
-complete -c x.py -n "__fish_x.py_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r
+complete -c x.py -n "__fish_x.py_using_subcommand test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 154f4f95eb5..f4b26fac0bc 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -339,7 +339,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;test' {
             [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
             [CompletionResult]::new('--compiletest-rustc-args', '--compiletest-rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running compiletest tests')
-            [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)')
+            [CompletionResult]::new('--extra-checks', '--extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix)')
             [CompletionResult]::new('--compare-mode', '--compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to')
             [CompletionResult]::new('--pass', '--pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode')
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index 177d60f9738..8fc4f052252 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -338,7 +338,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \
 '*--compiletest-rustc-args=[extra options to pass the compiler when running compiletest tests]:ARGS:_default' \
-'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS:_default' \
+'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell, shell\:lint, cpp, cpp\:fmt, spellcheck, spellcheck\:fix)]:EXTRA_CHECKS:_default' \
 '--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE:_default' \
 '--pass=[force {check,build,run}-pass tests to this mode]:check | build | run:_default' \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index c889f52b789..11d5b472d73 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -23,7 +23,7 @@ pub(crate) fn synthesize_blanket_impls(
     let ty = tcx.type_of(item_def_id);
 
     let mut blanket_impls = Vec::new();
-    for trait_def_id in tcx.all_traits() {
+    for trait_def_id in tcx.visible_traits() {
         if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id)
             || cx.generated_synthetics.contains(&(ty.skip_binder(), trait_def_id))
         {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3d027db2622..2ab827b3ace 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -66,8 +66,8 @@ use crate::visit_ast::Module as DocModule;
 pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
     let mut items: Vec<Item> = vec![];
     let mut inserted = FxHashSet::default();
-    items.extend(doc.foreigns.iter().map(|(item, renamed)| {
-        let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
+    items.extend(doc.foreigns.iter().map(|(item, renamed, import_id)| {
+        let item = clean_maybe_renamed_foreign_item(cx, item, *renamed, *import_id);
         if let Some(name) = item.name
             && (cx.render_options.document_hidden || !item.is_doc_hidden())
         {
@@ -89,7 +89,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
         Some(item)
     }));
 
-    // Split up imports from all other items.
+    // Split up glob imports from all other items.
     //
     // This covers the case where somebody does an import which should pull in an item,
     // but there's already an item with the same namespace and same name. Rust gives
@@ -1171,7 +1171,7 @@ fn clean_poly_fn_sig<'tcx>(
     // If this comes from a fn item, let's not perpetuate anon params from Rust 2015; use `_` for them.
     // If this comes from a fn ptr ty, we just keep params unnamed since it's more conventional stylistically.
     // Since the param name is not part of the semantic type, these params never bear a name unlike
-    // in the HIR case, thus we can't peform any fancy fallback logic unlike `clean_bare_fn_ty`.
+    // in the HIR case, thus we can't perform any fancy fallback logic unlike `clean_bare_fn_ty`.
     let fallback = did.map(|_| kw::Underscore);
 
     let params = sig
@@ -2746,7 +2746,8 @@ fn add_without_unwanted_attributes<'hir>(
                     attrs.push((Cow::Owned(attr), import_parent));
                 }
             }
-            hir::Attribute::Parsed(..) if is_inline => {
+            // FIXME: make sure to exclude `#[cfg_trace]` here when it is ported to the new parsers
+            hir::Attribute::Parsed(..) => {
                 attrs.push((Cow::Owned(attr), import_parent));
             }
             _ => {}
@@ -2761,7 +2762,6 @@ fn clean_maybe_renamed_item<'tcx>(
     import_id: Option<LocalDefId>,
 ) -> Vec<Item> {
     use hir::ItemKind;
-
     fn get_name(
         cx: &DocContext<'_>,
         item: &hir::Item<'_>,
@@ -2973,6 +2973,7 @@ fn clean_extern_crate<'tcx>(
         && !cx.is_json_output();
 
     let krate_owner_def_id = krate.owner_id.def_id;
+
     if please_inline
         && let Some(items) = inline::try_inline(
             cx,
@@ -3134,6 +3135,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
     cx: &mut DocContext<'tcx>,
     item: &hir::ForeignItem<'tcx>,
     renamed: Option<Symbol>,
+    import_id: Option<LocalDefId>,
 ) -> Item {
     let def_id = item.owner_id.to_def_id();
     cx.with_param_env(def_id, |cx| {
@@ -3149,11 +3151,13 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
             hir::ForeignItemKind::Type => ForeignTypeItem,
         };
 
-        Item::from_def_id_and_parts(
-            item.owner_id.def_id.to_def_id(),
-            Some(renamed.unwrap_or(item.ident.name)),
-            kind,
+        generate_item_with_correct_attrs(
             cx,
+            kind,
+            item.owner_id.def_id.to_def_id(),
+            item.ident.name,
+            import_id,
+            renamed,
         )
     })
 }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 600c564d714..c9530216968 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -7,7 +7,7 @@ use arrayvec::ArrayVec;
 use itertools::Either;
 use rustc_abi::{ExternAbi, VariantIdx};
 use rustc_attr_data_structures::{
-    AttributeKind, ConstStability, Deprecation, Stability, StableSince,
+    AttributeKind, ConstStability, Deprecation, Stability, StableSince, find_attr,
 };
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -24,7 +24,7 @@ use rustc_resolve::rustdoc::{
 };
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::{Ident, Symbol, kw, sym};
+use rustc_span::symbol::{Symbol, kw, sym};
 use rustc_span::{DUMMY_SP, FileName, Loc};
 use thin_vec::ThinVec;
 use tracing::{debug, trace};
@@ -770,6 +770,17 @@ impl Item {
                         hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None,
                         // We have separate pretty-printing logic for `#[repr(..)]` attributes.
                         hir::Attribute::Parsed(AttributeKind::Repr(..)) => None,
+                        // target_feature is special-cased because cargo-semver-checks uses it
+                        hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => {
+                            let mut output = String::new();
+                            for (i, (feature, _)) in features.iter().enumerate() {
+                                if i != 0 {
+                                    output.push_str(", ");
+                                }
+                                output.push_str(&format!("enable=\"{}\"", feature.as_str()));
+                            }
+                            Some(format!("#[target_feature({output})]"))
+                        }
                         _ => Some({
                             let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
                             assert_eq!(s.pop(), Some('\n'));
@@ -1075,16 +1086,10 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
 
     // treat #[target_feature(enable = "feat")] attributes as if they were
     // #[doc(cfg(target_feature = "feat"))] attributes as well
-    for attr in hir_attr_lists(attrs, sym::target_feature) {
-        if attr.has_name(sym::enable) && attr.value_str().is_some() {
-            // Clone `enable = "feat"`, change to `target_feature = "feat"`.
-            // Unwrap is safe because `value_str` succeeded above.
-            let mut meta = attr.meta_item().unwrap().clone();
-            meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
-
-            if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
-                cfg &= feat_cfg;
-            }
+    if let Some(features) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features)
+    {
+        for (feature, _) in features {
+            cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
         }
     }
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index cf3c4ac97af..bd57bb21e63 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -353,7 +353,7 @@ pub(crate) fn run_global_ctxt(
     rustc_passes::stability::check_unused_or_stable_features(tcx);
 
     let auto_traits =
-        tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect();
+        tcx.visible_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect();
 
     let mut ctxt = DocContext {
         tcx,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 1b5c9fd4664..9b4d2533954 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -858,7 +858,7 @@ impl ScrapedDocTest {
             item_path.push(' ');
         }
         let name =
-            format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly());
+            format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionally());
 
         Self { filename, line, langstr, text, name, span, global_crate_attrs }
     }
diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs
index 925fb6fee2c..3d046ec1835 100644
--- a/src/librustdoc/doctest/extracted.rs
+++ b/src/librustdoc/doctest/extracted.rs
@@ -62,7 +62,7 @@ impl ExtractedDocTests {
             Some(&opts.crate_name),
         );
         self.doctests.push(ExtractedDocTest {
-            file: filename.prefer_remapped_unconditionaly().to_string(),
+            file: filename.prefer_remapped_unconditionally().to_string(),
             line,
             doctest_attributes: langstr.into(),
             doctest_code: match wrapped {
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index b81fc5a0a71..ea2aa963edd 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -35,10 +35,9 @@ impl ExternalHtml {
     ) -> Option<ExternalHtml> {
         let codes = ErrorCodes::from(nightly_build);
         let ih = load_external_files(in_header, dcx)?;
-        let bc = load_external_files(before_content, dcx)?;
-        let m_bc = load_external_files(md_before_content, dcx)?;
-        let bc = format!(
-            "{bc}{}",
+        let bc = {
+            let mut bc = load_external_files(before_content, dcx)?;
+            let m_bc = load_external_files(md_before_content, dcx)?;
             Markdown {
                 content: &m_bc,
                 links: &[],
@@ -48,12 +47,13 @@ impl ExternalHtml {
                 playground,
                 heading_offset: HeadingOffset::H2,
             }
-            .into_string()
-        );
-        let ac = load_external_files(after_content, dcx)?;
-        let m_ac = load_external_files(md_after_content, dcx)?;
-        let ac = format!(
-            "{ac}{}",
+            .write_into(&mut bc)
+            .unwrap();
+            bc
+        };
+        let ac = {
+            let mut ac = load_external_files(after_content, dcx)?;
+            let m_ac = load_external_files(md_after_content, dcx)?;
             Markdown {
                 content: &m_ac,
                 links: &[],
@@ -63,8 +63,10 @@ impl ExternalHtml {
                 playground,
                 heading_offset: HeadingOffset::H2,
             }
-            .into_string()
-        );
+            .write_into(&mut ac)
+            .unwrap();
+            ac
+        };
         Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
     }
 }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index f626e07b000..e41435de29c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -21,13 +21,14 @@
 //!     playground: &None,
 //!     heading_offset: HeadingOffset::H2,
 //! };
-//! let html = md.into_string();
+//! let mut html = String::new();
+//! md.write_into(&mut html).unwrap();
 //! // ... something using html
 //! ```
 
 use std::borrow::Cow;
 use std::collections::VecDeque;
-use std::fmt::Write;
+use std::fmt::{self, Write};
 use std::iter::Peekable;
 use std::ops::{ControlFlow, Range};
 use std::path::PathBuf;
@@ -1328,16 +1329,13 @@ impl LangString {
 }
 
 impl<'a> Markdown<'a> {
-    pub fn into_string(self) -> String {
+    pub fn write_into(self, f: impl fmt::Write) -> fmt::Result {
         // This is actually common enough to special-case
         if self.content.is_empty() {
-            return String::new();
+            return Ok(());
         }
 
-        let mut s = String::with_capacity(self.content.len() * 3 / 2);
-        html::push_html(&mut s, self.into_iter());
-
-        s
+        html::write_html_fmt(f, self.into_iter())
     }
 
     fn into_iter(self) -> CodeBlocks<'a, 'a, impl Iterator<Item = Event<'a>>> {
@@ -1453,19 +1451,20 @@ impl MarkdownWithToc<'_> {
 
         (toc.into_toc(), s)
     }
-    pub(crate) fn into_string(self) -> String {
+
+    pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
         let (toc, s) = self.into_parts();
-        format!("<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
+        write!(f, "<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
     }
 }
 
 impl MarkdownItemInfo<'_> {
-    pub(crate) fn into_string(self) -> String {
+    pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
         let MarkdownItemInfo(md, ids) = self;
 
         // This is actually common enough to special-case
         if md.is_empty() {
-            return String::new();
+            return Ok(());
         }
         let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
 
@@ -1475,8 +1474,6 @@ impl MarkdownItemInfo<'_> {
             _ => event,
         });
 
-        let mut s = String::with_capacity(md.len() * 3 / 2);
-
         ids.handle_footnotes(|ids, existing_footnotes| {
             let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
             let p = footnotes::Footnotes::new(p, existing_footnotes);
@@ -1484,10 +1481,8 @@ impl MarkdownItemInfo<'_> {
             let p = p.filter(|event| {
                 !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
             });
-            html::push_html(&mut s, p);
-        });
-
-        s
+            html::write_html_fmt(&mut f, p)
+        })
     }
 }
 
diff --git a/src/librustdoc/html/markdown/footnotes.rs b/src/librustdoc/html/markdown/footnotes.rs
index ded0585ddcc..7ee012c4da2 100644
--- a/src/librustdoc/html/markdown/footnotes.rs
+++ b/src/librustdoc/html/markdown/footnotes.rs
@@ -38,7 +38,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Footnotes<'a, I> {
         let key = key.to_owned();
         let FootnoteDef { content, id } =
             self.footnotes.entry(key).or_insert(FootnoteDef { content: Vec::new(), id: new_id });
-        // Don't allow changing the ID of existing entrys, but allow changing the contents.
+        // Don't allow changing the ID of existing entries, but allow changing the contents.
         (content, *id)
     }
 
@@ -82,7 +82,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                     return Some((self.handle_footnote_reference(reference), range));
                 }
                 Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
-                    // When we see a footnote definition, collect the assocated content, and store
+                    // When we see a footnote definition, collect the associated content, and store
                     // that for rendering later.
                     let content = self.collect_footnote_def();
                     let (entry_content, _) = self.get_entry(&def);
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 784d0c5d21e..61fd4287463 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -297,7 +297,8 @@ fn test_lang_string_tokenizer() {
 fn test_header() {
     fn t(input: &str, expect: &str) {
         let mut map = IdMap::new();
-        let output = Markdown {
+        let mut output = String::new();
+        Markdown {
             content: input,
             links: &[],
             ids: &mut map,
@@ -306,7 +307,8 @@ fn test_header() {
             playground: &None,
             heading_offset: HeadingOffset::H2,
         }
-        .into_string();
+        .write_into(&mut output)
+        .unwrap();
         assert_eq!(output, expect, "original: {}", input);
     }
 
@@ -348,7 +350,8 @@ fn test_header() {
 fn test_header_ids_multiple_blocks() {
     let mut map = IdMap::new();
     fn t(map: &mut IdMap, input: &str, expect: &str) {
-        let output = Markdown {
+        let mut output = String::new();
+        Markdown {
             content: input,
             links: &[],
             ids: map,
@@ -357,7 +360,8 @@ fn test_header_ids_multiple_blocks() {
             playground: &None,
             heading_offset: HeadingOffset::H2,
         }
-        .into_string();
+        .write_into(&mut output)
+        .unwrap();
         assert_eq!(output, expect, "original: {}", input);
     }
 
@@ -466,7 +470,8 @@ fn test_plain_text_summary() {
 fn test_markdown_html_escape() {
     fn t(input: &str, expect: &str) {
         let mut idmap = IdMap::new();
-        let output = MarkdownItemInfo(input, &mut idmap).into_string();
+        let mut output = String::new();
+        MarkdownItemInfo(input, &mut idmap).write_into(&mut output).unwrap();
         assert_eq!(output, expect, "original: {}", input);
     }
 
@@ -496,7 +501,8 @@ fn test_find_testable_code_line() {
 fn test_ascii_with_prepending_hashtag() {
     fn t(input: &str, expect: &str) {
         let mut map = IdMap::new();
-        let output = Markdown {
+        let mut output = String::new();
+        Markdown {
             content: input,
             links: &[],
             ids: &mut map,
@@ -505,7 +511,8 @@ fn test_ascii_with_prepending_hashtag() {
             playground: &None,
             heading_offset: HeadingOffset::H2,
         }
-        .into_string();
+        .write_into(&mut output)
+        .unwrap();
         assert_eq!(output, expect, "original: {}", input);
     }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index ed58bae70bd..6a1fad06ae3 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -508,22 +508,21 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
       the Rustdoc book]({DOC_RUST_LANG_ORG_VERSION}/rustdoc/scraped-examples.html)."
     ));
 
-    let mut ids = IdMap::default();
     format!(
         "<div class=\"main-heading\">\
              <h1>About scraped examples</h1>\
          </div>\
          <div>{}</div>",
-        Markdown {
+        fmt::from_fn(|f| Markdown {
             content: &content,
             links: &[],
-            ids: &mut ids,
+            ids: &mut IdMap::default(),
             error_codes: shared.codes,
             edition: shared.edition(),
             playground: &shared.playground,
             heading_offset: HeadingOffset::H1,
         }
-        .into_string()
+        .write_into(f))
     )
 }
 
@@ -555,20 +554,18 @@ fn render_markdown(
     heading_offset: HeadingOffset,
 ) -> impl fmt::Display {
     fmt::from_fn(move |f| {
-        write!(
-            f,
-            "<div class=\"docblock\">{}</div>",
-            Markdown {
-                content: md_text,
-                links: &links,
-                ids: &mut cx.id_map.borrow_mut(),
-                error_codes: cx.shared.codes,
-                edition: cx.shared.edition(),
-                playground: &cx.shared.playground,
-                heading_offset,
-            }
-            .into_string()
-        )
+        f.write_str("<div class=\"docblock\">")?;
+        Markdown {
+            content: md_text,
+            links: &links,
+            ids: &mut cx.id_map.borrow_mut(),
+            error_codes: cx.shared.codes,
+            edition: cx.shared.edition(),
+            playground: &cx.shared.playground,
+            heading_offset,
+        }
+        .write_into(&mut *f)?;
+        f.write_str("</div>")
     })
 }
 
@@ -752,7 +749,7 @@ fn short_item_info(
             let mut id_map = cx.id_map.borrow_mut();
             let html = MarkdownItemInfo(note, &mut id_map);
             message.push_str(": ");
-            message.push_str(&html.into_string());
+            html.write_into(&mut message).unwrap();
         }
         extra_info.push(ShortItemInfo::Deprecation { message });
     }
@@ -1947,7 +1944,7 @@ fn render_impl(
         // 3. Functions
         //
         // This order is because you can have associated constants used in associated types (like array
-        // length), and both in associcated functions. So with this order, when reading from top to
+        // length), and both in associated functions. So with this order, when reading from top to
         // bottom, you should see items definitions before they're actually used most of the time.
         let mut assoc_types = Vec::new();
         let mut methods = Vec::new();
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 606a9113908..41c3f03b91b 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -443,7 +443,7 @@ impl CratesIndexPart {
             .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page")
     }
 
-    /// Might return parts that are duplicate with ones in prexisting index.html
+    /// Might return parts that are duplicate with ones in preexisting index.html
     fn get(crate_name: &str, external_crates: &[String]) -> Result<PartsAndLocations<Self>, Error> {
         let mut ret = PartsAndLocations::default();
         let path = Path::new("index.html");
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 7be83b65fbf..99b3da8b2cd 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -8,6 +8,8 @@
 	3. Copy the filenames with updated suffixes from the directory.
 */
 
+/* ignore-tidy-filelength */
+
 :root {
 	--nav-sub-mobile-padding: 8px;
 	--search-typename-width: 6.75rem;
@@ -915,32 +917,30 @@ ul.block, .block li, .block ul {
 	overflow: auto;
 }
 
-.example-wrap.digits-1:not(.hide-lines) [data-nosnippet] {
-	width: calc(1ch + var(--line-number-padding) * 2);
-}
-.example-wrap.digits-2:not(.hide-lines) [data-nosnippet] {
-	width: calc(2ch + var(--line-number-padding) * 2);
-}
-.example-wrap.digits-3:not(.hide-lines) [data-nosnippet] {
-	width: calc(3ch + var(--line-number-padding) * 2);
-}
-.example-wrap.digits-4:not(.hide-lines) [data-nosnippet] {
-	width: calc(4ch + var(--line-number-padding) * 2);
-}
-.example-wrap.digits-5:not(.hide-lines) [data-nosnippet] {
-	width: calc(5ch + var(--line-number-padding) * 2);
-}
-.example-wrap.digits-6:not(.hide-lines) [data-nosnippet] {
-	width: calc(6ch + var(--line-number-padding) * 2);
+.example-wrap code {
+	position: relative;
 }
-.example-wrap.digits-7:not(.hide-lines) [data-nosnippet] {
-	width: calc(7ch + var(--line-number-padding) * 2);
+.example-wrap pre code span {
+	display: inline;
 }
-.example-wrap.digits-8:not(.hide-lines) [data-nosnippet] {
-	width: calc(8ch + var(--line-number-padding) * 2);
+
+.example-wrap.digits-1 { --example-wrap-digits-count: 1ch; }
+.example-wrap.digits-2 { --example-wrap-digits-count: 2ch; }
+.example-wrap.digits-3 { --example-wrap-digits-count: 3ch; }
+.example-wrap.digits-4 { --example-wrap-digits-count: 4ch; }
+.example-wrap.digits-5 { --example-wrap-digits-count: 5ch; }
+.example-wrap.digits-6 { --example-wrap-digits-count: 6ch; }
+.example-wrap.digits-7 { --example-wrap-digits-count: 7ch; }
+.example-wrap.digits-8 { --example-wrap-digits-count: 8ch; }
+.example-wrap.digits-9 { --example-wrap-digits-count: 9ch; }
+
+.example-wrap [data-nosnippet] {
+	width: calc(var(--example-wrap-digits-count) + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-9:not(.hide-lines) [data-nosnippet] {
-	width: calc(9ch + var(--line-number-padding) * 2);
+.example-wrap pre > code {
+	padding-left: calc(
+		var(--example-wrap-digits-count) + var(--line-number-padding) * 2
+		+ var(--line-number-right-margin));
 }
 
 .example-wrap [data-nosnippet] {
@@ -953,63 +953,25 @@ ul.block, .block li, .block ul {
 	-ms-user-select: none;
 	user-select: none;
 	padding: 0 var(--line-number-padding);
-}
-.example-wrap [data-nosnippet]:target {
-	border-right: none;
+	position: absolute;
+	left: 0;
 }
 .example-wrap .line-highlighted[data-nosnippet] {
 	background-color: var(--src-line-number-highlighted-background-color);
 }
-:root.word-wrap-source-code .example-wrap [data-nosnippet] {
-	position: absolute;
-	left: 0;
-}
-.word-wrap-source-code .example-wrap pre > code {
+.example-wrap pre > code {
 	position: relative;
-	word-break: break-all;
+	display: block;
 }
 :root.word-wrap-source-code .example-wrap pre > code {
-	display: block;
+	word-break: break-all;
 	white-space: pre-wrap;
 }
 :root.word-wrap-source-code .example-wrap pre > code * {
 	word-break: break-all;
 }
-:root.word-wrap-source-code .example-wrap.digits-1 pre > code {
-	padding-left: calc(
-		1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-2 pre > code {
-	padding-left: calc(
-		2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-3 pre > code {
-	padding-left: calc(
-		3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-4 pre > code {
-	padding-left: calc(
-		4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-5 pre > code {
-	padding-left: calc(
-		5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-6 pre > code {
-	padding-left: calc(
-		6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-7 pre > code {
-	padding-left: calc(
-		7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-8 pre > code {
-	padding-left: calc(
-		8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
-}
-:root.word-wrap-source-code .example-wrap.digits-9 pre > code {
-	padding-left: calc(
-		9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+.example-wrap [data-nosnippet]:target {
+	border-right: none;
 }
 .example-wrap.hide-lines [data-nosnippet] {
 	display: none;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 2de8f836da3..3c4af0dc612 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1719,7 +1719,7 @@ function preLoadCss(cssUrl) {
     // 300px, and the RUSTDOC_MOBILE_BREAKPOINT is 700px, so BODY_MIN must be
     // at most 400px. Otherwise, it would start out at the default size, then
     // grabbing the resize handle would suddenly cause it to jank to
-    // its contraint-generated maximum.
+    // its constraint-generated maximum.
     const RUSTDOC_MOBILE_BREAKPOINT = 700;
     const BODY_MIN = 400;
     // At half-way past the minimum size, vanish the sidebar entirely
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index bbcd96040be..ca2512e5ab6 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -464,7 +464,7 @@ declare namespace rustdoc {
 
     /**
      * Maps from crate names to trait implementation data.
-     * Provied by generated `trait.impl` files.
+     * Provided by generated `trait.impl` files.
      */
     type Implementors = {
         [key: string]: Array<[string, number, Array<string>]>
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 76eac084907..4ca2c104888 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -8,7 +8,7 @@
 //!
 //! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files
 
-use std::fmt::Write as _;
+use std::fmt::{self, Write as _};
 use std::fs::{File, create_dir_all, read_to_string};
 use std::io::prelude::*;
 use std::path::Path;
@@ -77,32 +77,33 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
     }
     let title = metadata[0];
 
-    let mut ids = IdMap::new();
     let error_codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
-    let text = if !options.markdown_no_toc {
-        MarkdownWithToc {
-            content: text,
-            links: &[],
-            ids: &mut ids,
-            error_codes,
-            edition,
-            playground: &playground,
-        }
-        .into_string()
-    } else {
-        Markdown {
-            content: text,
-            links: &[],
-            ids: &mut ids,
-            error_codes,
-            edition,
-            playground: &playground,
-            heading_offset: HeadingOffset::H1,
+    let text = fmt::from_fn(|f| {
+        if !options.markdown_no_toc {
+            MarkdownWithToc {
+                content: text,
+                links: &[],
+                ids: &mut IdMap::new(),
+                error_codes,
+                edition,
+                playground: &playground,
+            }
+            .write_into(f)
+        } else {
+            Markdown {
+                content: text,
+                links: &[],
+                ids: &mut IdMap::new(),
+                error_codes,
+                edition,
+                playground: &playground,
+                heading_offset: HeadingOffset::H1,
+            }
+            .write_into(f)
         }
-        .into_string()
-    };
+    });
 
-    let err = write!(
+    let res = write!(
         &mut out,
         r#"<!DOCTYPE html>
 <html lang="en">
@@ -130,15 +131,10 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
 </body>
 </html>"#,
         title = Escape(title),
-        css = css,
         in_header = options.external_html.in_header,
         before_content = options.external_html.before_content,
-        text = text,
         after_content = options.external_html.after_content,
     );
 
-    match err {
-        Err(e) => Err(format!("cannot write to `{output}`: {e}", output = output.display())),
-        Ok(_) => Ok(()),
-    }
+    res.map_err(|e| format!("cannot write to `{output}`: {e}", output = output.display()))
 }
diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs
index 7f5c7da3634..b53e3b4e3d7 100644
--- a/src/librustdoc/passes/strip_aliased_non_local.rs
+++ b/src/librustdoc/passes/strip_aliased_non_local.rs
@@ -42,7 +42,7 @@ struct NonLocalStripper<'tcx> {
 impl DocFolder for NonLocalStripper<'_> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         // If not local, we want to respect the original visibility of
-        // the field and not the one given by the user for the currrent crate.
+        // the field and not the one given by the user for the current crate.
         //
         // FIXME(#125009): Not-local should probably consider same Cargo workspace
         if let Some(def_id) = i.def_id()
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 692ce21d6cf..3388ae46f05 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -168,7 +168,7 @@ impl DocFolder for Stripper<'_, '_> {
                 self.update_retained = old;
                 if ret.item_id == clean::ItemId::DefId(CRATE_DEF_ID.into()) {
                     // We don't strip the current crate, even if it has `#[doc(hidden)]`.
-                    debug!("strip_hidden: Not strippping local crate");
+                    debug!("strip_hidden: Not stripping local crate");
                     Some(ret)
                 } else {
                     Some(strip_item(ret))
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 5b52e785b8f..2889bfae7b0 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -38,9 +38,18 @@ pub(crate) struct Module<'hir> {
         (LocalDefId, Option<Symbol>),
         (&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>),
     >,
-    /// Same as for `items`.
+
+    /// (def_id, renamed) -> (res, local_import_id)
+    ///
+    /// `inlined_foreigns` only contains `extern` items
+    /// that are cross-crate inlined.
+    ///
+    /// Locally inlined `extern` items are
+    /// stored in `foreigns` with the `import_id` set,
+    /// analogous to how `items` is.
     pub(crate) inlined_foreigns: FxIndexMap<(DefId, Option<Symbol>), (Res, LocalDefId)>,
-    pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
+    /// (item, renamed, import_id)
+    pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>, Option<LocalDefId>)>,
 }
 
 impl Module<'_> {
@@ -327,7 +336,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
             Node::ForeignItem(it) if !glob => {
                 let prev = mem::replace(&mut self.inlining, true);
-                self.visit_foreign_item_inner(it, renamed);
+                self.visit_foreign_item_inner(it, renamed, Some(def_id));
                 self.inlining = prev;
                 true
             }
@@ -432,7 +441,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             hir::ItemKind::ForeignMod { items, .. } => {
                 for item in items {
                     let item = tcx.hir_foreign_item(item.id);
-                    self.visit_foreign_item_inner(item, None);
+                    self.visit_foreign_item_inner(item, None, None);
                 }
             }
             // If we're inlining, skip private items.
@@ -527,10 +536,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         &mut self,
         item: &'tcx hir::ForeignItem<'_>,
         renamed: Option<Symbol>,
+        import_id: Option<LocalDefId>,
     ) {
         // If inlining we only want to include public functions.
         if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() {
-            self.modules.last_mut().unwrap().foreigns.push((item, renamed));
+            self.modules.last_mut().unwrap().foreigns.push((item, renamed, import_id));
         }
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index dc240dd067b..8453165818b 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -98,6 +98,7 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) {
 /// 17 |     std::mem::forget(seven);
 ///    |     ^^^^^^^^^^^^^^^^^^^^^^^
 /// ```
+#[track_caller]
 pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
     cx.span_lint(lint, sp, |diag| {
@@ -143,6 +144,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
 ///    |
 ///    = help: consider using `f64::NAN` if you would like a constant representing NaN
 /// ```
+#[track_caller]
 pub fn span_lint_and_help<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
@@ -203,6 +205,7 @@ pub fn span_lint_and_help<T: LintContext>(
 /// 10 |     forget(&SomeStruct);
 ///    |            ^^^^^^^^^^^
 /// ```
+#[track_caller]
 pub fn span_lint_and_note<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
@@ -244,6 +247,7 @@ pub fn span_lint_and_note<T: LintContext>(
 /// If you're unsure which function you should use, you can test if the `#[expect]` attribute works
 /// where you would expect it to.
 /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
+#[track_caller]
 pub fn span_lint_and_then<C, S, M, F>(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F)
 where
     C: LintContext,
@@ -286,6 +290,7 @@ where
 /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
 /// the compiler check lint level attributes at the place of the expression and
 /// the `#[allow]` will work.
+#[track_caller]
 pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into<DiagMessage>) {
     #[expect(clippy::disallowed_methods)]
     cx.tcx.node_span_lint(lint, hir_id, sp, |diag| {
@@ -321,6 +326,7 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s
 /// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
 /// the compiler check lint level attributes at the place of the expression and
 /// the `#[allow]` will work.
+#[track_caller]
 pub fn span_lint_hir_and_then(
     cx: &LateContext<'_>,
     lint: &'static Lint,
@@ -374,6 +380,7 @@ pub fn span_lint_hir_and_then(
 ///     = note: `-D fold-any` implied by `-D warnings`
 /// ```
 #[cfg_attr(not(debug_assertions), expect(clippy::collapsible_span_lint_calls))]
+#[track_caller]
 pub fn span_lint_and_sugg<T: LintContext>(
     cx: &T,
     lint: &'static Lint,
diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs
new file mode 100644
index 00000000000..2e67fb65efc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs
@@ -0,0 +1,22 @@
+//@compile-flags: -Z track-diagnostics
+//@no-rustfix
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+#![warn(clippy::let_and_return, clippy::unnecessary_cast)]
+
+fn main() {
+    // Check the provenance of a lint sent through `LintContext::span_lint()`
+    let a = 3u32;
+    let b = a as u32;
+    //~^ unnecessary_cast
+    
+    // Check the provenance of a lint sent through `TyCtxt::node_span_lint()`
+    let c = {
+        let d = 42;
+        d
+        //~^ let_and_return
+    };
+}
diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
new file mode 100644
index 00000000000..f3aca685417
--- /dev/null
+++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr
@@ -0,0 +1,29 @@
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> tests/ui/track-diagnostics-clippy.rs:LL:CC
+   |
+LL |     let b = a as u32;
+   |             ^^^^^^^^ help: try: `a`
+-Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs:LL:CC
+   |
+   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/track-diagnostics-clippy.rs:LL:CC
+   |
+LL |         let d = 42;
+   |         ----------- unnecessary `let` binding
+LL |         d
+   |         ^
+-Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/returns.rs:LL:CC
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
+help: return the expression directly
+   |
+LL ~         
+LL ~         42
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 2ecb4fc8652..adf2a7bffef 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -1,6 +1,6 @@
 /// This was originally generated by collecting directives from ui tests and then extracting their
 /// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
-/// a best-effort approximation for diagnostics. Add new headers to this list when needed.
+/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
 const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     // tidy-alphabetical-start
     "add-core-stubs",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/directives.rs
index 5636a146b0f..a6242cf0c22 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -11,10 +11,10 @@ use tracing::*;
 
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
+use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
+use crate::directives::needs::CachedNeedsConditions;
 use crate::errors::ErrorKind;
 use crate::executor::{CollectedTestDesc, ShouldPanic};
-use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
-use crate::header::needs::CachedNeedsConditions;
 use crate::help;
 use crate::util::static_regex;
 
@@ -24,11 +24,11 @@ mod needs;
 #[cfg(test)]
 mod tests;
 
-pub struct HeadersCache {
+pub struct DirectivesCache {
     needs: CachedNeedsConditions,
 }
 
-impl HeadersCache {
+impl DirectivesCache {
     pub fn load(config: &Config) -> Self {
         Self { needs: CachedNeedsConditions::load(config) }
     }
@@ -54,7 +54,7 @@ impl EarlyProps {
     pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Self {
         let mut props = EarlyProps::default();
         let mut poisoned = false;
-        iter_header(
+        iter_directives(
             config.mode,
             &config.suite,
             &mut poisoned,
@@ -138,12 +138,12 @@ pub struct TestProps {
     pub incremental_dir: Option<Utf8PathBuf>,
     // If `true`, this test will use incremental compilation.
     //
-    // This can be set manually with the `incremental` header, or implicitly
+    // This can be set manually with the `incremental` directive, or implicitly
     // by being a part of an incremental mode test. Using the `incremental`
-    // header should be avoided if possible; using an incremental mode test is
+    // directive should be avoided if possible; using an incremental mode test is
     // preferred. Incremental mode tests support multiple passes, which can
     // verify that the incremental cache can be loaded properly after being
-    // created. Just setting the header will only verify the behavior with
+    // created. Just setting the directive will only verify the behavior with
     // creating an incremental cache, but doesn't check that it is created
     // correctly.
     //
@@ -347,7 +347,7 @@ impl TestProps {
 
             let mut poisoned = false;
 
-            iter_header(
+            iter_directives(
                 config.mode,
                 &config.suite,
                 &mut poisoned,
@@ -642,11 +642,11 @@ impl TestProps {
         let check_ui = |mode: &str| {
             // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
             if config.mode != Mode::Ui && config.mode != Mode::Crashes {
-                panic!("`{}-fail` header is only supported in UI tests", mode);
+                panic!("`{}-fail` directive is only supported in UI tests", mode);
             }
         };
         if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") {
-            panic!("`compile-fail` header is useless in UI tests");
+            panic!("`compile-fail` directive is useless in UI tests");
         }
         let fail_mode = if config.parse_name_directive(ln, "check-fail") {
             check_ui("check");
@@ -662,7 +662,7 @@ impl TestProps {
         };
         match (self.fail_mode, fail_mode) {
             (None, Some(_)) => self.fail_mode = fail_mode,
-            (Some(_), Some(_)) => panic!("multiple `*-fail` headers in a single test"),
+            (Some(_), Some(_)) => panic!("multiple `*-fail` directives in a single test"),
             (_, None) => {}
         }
     }
@@ -674,10 +674,10 @@ impl TestProps {
             (Mode::Codegen, "build-pass") => (),
             (Mode::Incremental, _) => {
                 if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) {
-                    panic!("`{s}` header is only supported in `cfail` incremental tests")
+                    panic!("`{s}` directive is only supported in `cfail` incremental tests")
                 }
             }
-            (mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"),
+            (mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"),
         };
         let pass_mode = if config.parse_name_directive(ln, "check-pass") {
             check_no_run("check-pass");
@@ -693,7 +693,7 @@ impl TestProps {
         };
         match (self.pass_mode, pass_mode) {
             (None, Some(_)) => self.pass_mode = pass_mode,
-            (Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"),
+            (Some(_), Some(_)) => panic!("multiple `*-pass` directives in a single test"),
             (_, None) => {}
         }
     }
@@ -794,7 +794,7 @@ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
     &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
 
 /// The (partly) broken-down contents of a line containing a test directive,
-/// which [`iter_header`] passes to its callback function.
+/// which [`iter_directives`] passes to its callback function.
 ///
 /// For example:
 ///
@@ -867,7 +867,7 @@ pub(crate) fn check_directive<'a>(
 
 const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
 
-fn iter_header(
+fn iter_directives(
     mode: Mode,
     _suite: &str,
     poisoned: &mut bool,
@@ -1163,8 +1163,7 @@ enum NormalizeKind {
     Stderr64bit,
 }
 
-/// Parses the regex and replacement values of a `//@ normalize-*` header,
-/// in the format:
+/// Parses the regex and replacement values of a `//@ normalize-*` directive, in the format:
 /// ```text
 /// "REGEX" -> "REPLACEMENT"
 /// ```
@@ -1373,7 +1372,7 @@ where
 
 pub(crate) fn make_test_description<R: Read>(
     config: &Config,
-    cache: &HeadersCache,
+    cache: &DirectivesCache,
     name: String,
     path: &Utf8Path,
     src: R,
@@ -1387,7 +1386,7 @@ pub(crate) fn make_test_description<R: Read>(
     let mut local_poisoned = false;
 
     // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives.
-    iter_header(
+    iter_directives(
         config.mode,
         &config.suite,
         &mut local_poisoned,
diff --git a/src/tools/compiletest/src/header/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs
index 0e1f3a785f8..cdb75f6ffa9 100644
--- a/src/tools/compiletest/src/header/auxiliary.rs
+++ b/src/tools/compiletest/src/directives/auxiliary.rs
@@ -3,8 +3,8 @@
 
 use std::iter;
 
+use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 use crate::common::Config;
-use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 
 /// Properties parsed from `aux-*` test directives.
 #[derive(Clone, Debug, Default)]
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs
index f1f1384afb9..35f6a9e1644 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/directives/cfg.rs
@@ -1,7 +1,7 @@
 use std::collections::HashSet;
 
 use crate::common::{CompareMode, Config, Debugger};
-use crate::header::IgnoreDecision;
+use crate::directives::IgnoreDecision;
 
 const EXTRA_ARCHS: &[&str] = &["spirv"];
 
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/directives/needs.rs
index b1165f4bb18..ee46f4c70cb 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/directives/needs.rs
@@ -1,5 +1,5 @@
 use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
-use crate::header::{IgnoreDecision, llvm_has_libzstd};
+use crate::directives::{IgnoreDecision, llvm_has_libzstd};
 
 pub(super) fn handle_needs(
     cache: &CachedNeedsConditions,
diff --git a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs
index fea66a5e07b..fea66a5e07b 100644
--- a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/error_annotation.rs
diff --git a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs
index 99834b14c1e..99834b14c1e 100644
--- a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/known_directive.rs
diff --git a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile
index 4b565e0e6df..4b565e0e6df 100644
--- a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile
+++ b/src/tools/compiletest/src/directives/test-auxillary/not_rs.Makefile
diff --git a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs
index d4406031043..d4406031043 100644
--- a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs
+++ b/src/tools/compiletest/src/directives/test-auxillary/unknown_directive.rs
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/directives/tests.rs
index 31b49b09bcd..d4570f82677 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/directives/tests.rs
@@ -4,7 +4,7 @@ use camino::Utf8Path;
 use semver::Version;
 
 use super::{
-    EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header,
+    DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives,
     parse_normalize_rule,
 };
 use crate::common::{Config, Debugger, Mode};
@@ -17,9 +17,9 @@ fn make_test_description<R: Read>(
     src: R,
     revision: Option<&str>,
 ) -> CollectedTestDesc {
-    let cache = HeadersCache::load(config);
+    let cache = DirectivesCache::load(config);
     let mut poisoned = false;
-    let test = crate::header::make_test_description(
+    let test = crate::directives::make_test_description(
         config,
         &cache,
         name,
@@ -785,7 +785,7 @@ fn threads_support() {
 
 fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) {
     let rdr = std::io::Cursor::new(&buf);
-    iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
+    iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
 }
 
 #[test]
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 09de3eb4c70..dfce4b8b408 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -12,9 +12,9 @@ pub mod common;
 pub mod compute_diff;
 mod debuggers;
 pub mod diagnostics;
+pub mod directives;
 pub mod errors;
 mod executor;
-pub mod header;
 mod json;
 mod raise_fd_limit;
 mod read2;
@@ -37,13 +37,13 @@ use rayon::iter::{ParallelBridge, ParallelIterator};
 use tracing::debug;
 use walkdir::WalkDir;
 
-use self::header::{EarlyProps, make_test_description};
+use self::directives::{EarlyProps, make_test_description};
 use crate::common::{
     CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
     output_base_dir, output_relative_path,
 };
+use crate::directives::DirectivesCache;
 use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
-use crate::header::HeadersCache;
 use crate::util::logv;
 
 /// Creates the `Config` instance for this invocation of compiletest.
@@ -254,8 +254,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
         Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
     };
     let llvm_version =
-        matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else(
-            || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
+        matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else(
+            || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
         );
 
     let run_ignored = matches.opt_present("ignored");
@@ -618,7 +618,7 @@ pub fn run_tests(config: Arc<Config>) {
 /// Read-only context data used during test collection.
 struct TestCollectorCx {
     config: Arc<Config>,
-    cache: HeadersCache,
+    cache: DirectivesCache,
     common_inputs_stamp: Stamp,
     modified_tests: Vec<Utf8PathBuf>,
 }
@@ -654,7 +654,7 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest>
         modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| {
             fatal!("modified_tests: {}: {err}", config.src_test_suite_root);
         });
-    let cache = HeadersCache::load(&config);
+    let cache = DirectivesCache::load(&config);
 
     let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests };
     let collector = collect_tests_from_dir(&cx, &cx.config.src_test_suite_root, Utf8Path::new(""))
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 53b5990d3cd..f8bf4ee3022 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -23,8 +23,8 @@ use crate::common::{
     output_base_dir, output_base_name, output_testname_unique,
 };
 use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
+use crate::directives::TestProps;
 use crate::errors::{Error, ErrorKind, load_errors};
-use crate::header::TestProps;
 use crate::read2::{Truncated, read2_abbreviated};
 use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
 use crate::{ColorConfig, help, json, stamp_file_path, warning};
@@ -2039,7 +2039,7 @@ impl<'test> TestCx<'test> {
         // Provide more context on failures.
         filecheck.args(&["--dump-input-context", "100"]);
 
-        // Add custom flags supplied by the `filecheck-flags:` test header.
+        // Add custom flags supplied by the `filecheck-flags:` test directive.
         filecheck.args(&self.props.filecheck_flags);
 
         // FIXME(jieyouxu): don't pass an empty Path
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 31240dff9a1..d9e1e4dfc8d 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -49,7 +49,7 @@ impl TestCx<'_> {
             std::fs::remove_file(pdb_file).unwrap();
         }
 
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compile_result = self.compile_test(should_run, Emit::None);
         if !compile_result.status.success() {
@@ -135,7 +135,7 @@ impl TestCx<'_> {
             .unwrap_or_else(|e| self.fatal(&e));
         let mut cmds = dbg_cmds.commands.join("\n");
 
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compiler_run_result = self.compile_test(should_run, Emit::None);
         if !compiler_run_result.status.success() {
@@ -359,7 +359,7 @@ impl TestCx<'_> {
     }
 
     fn run_debuginfo_lldb_test_no_opt(&self) {
-        // compile test file (it should have 'compile-flags:-g' in the header)
+        // compile test file (it should have 'compile-flags:-g' in the directive)
         let should_run = self.run_if_enabled();
         let compile_result = self.compile_test(should_run, Emit::None);
         if !compile_result.status.success() {
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index cc50a918f75..f6bc85cd051 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -52,10 +52,10 @@ impl TestCx<'_> {
             // don't test rustfix with nll right now
         } else if self.config.rustfix_coverage {
             // Find out which tests have `MachineApplicable` suggestions but are missing
-            // `run-rustfix` or `run-rustfix-only-machine-applicable` headers.
+            // `run-rustfix` or `run-rustfix-only-machine-applicable` directives.
             //
             // This will return an empty `Vec` in case the executed test file has a
-            // `compile-flags: --error-format=xxxx` header with a value other than `json`.
+            // `compile-flags: --error-format=xxxx` directive with a value other than `json`.
             let suggestions = get_suggestions_from_json(
                 &rustfix_input,
                 &HashSet::new(),
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index 1796120cf8a..3cc38fa087c 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -466,17 +466,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Some((alloc_id, Size::from_bytes(rel_offset)))
     }
 
-    /// Prepare all exposed memory for a native call.
-    /// This overapproximates the modifications which external code might make to memory:
-    /// We set all reachable allocations as initialized, mark all reachable provenances as exposed
-    /// and overwrite them with `Provenance::WILDCARD`.
-    fn prepare_exposed_for_native_call(&mut self) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        // We need to make a deep copy of this list, but it's fine; it also serves as scratch space
-        // for the search within `prepare_for_native_call`.
-        let exposed: Vec<AllocId> =
-            this.machine.alloc_addresses.get_mut().exposed.iter().copied().collect();
-        this.prepare_for_native_call(exposed)
+    /// Return a list of all exposed allocations.
+    fn exposed_allocs(&self) -> Vec<AllocId> {
+        let this = self.eval_context_ref();
+        this.machine.alloc_addresses.borrow().exposed.iter().copied().collect()
     }
 }
 
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index ed1851a19ae..4efa7dd4dcf 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -457,6 +457,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 throw_machine_stop!(TerminationInfo::Abort(format!("trace/breakpoint trap")))
             }
 
+            "assert_inhabited" | "assert_zero_valid" | "assert_mem_uninitialized_valid" => {
+                // Make these a NOP, so we get the better Miri-native error messages.
+            }
+
             _ => return interp_ok(EmulateItemResult::NotSupported),
         }
 
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index dd00b270b38..18d60915d20 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -104,7 +104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap()));
 
         let name = fn_instance.to_string();
-        let filename = lo.file.name.prefer_remapped_unconditionaly().to_string();
+        let filename = lo.file.name.prefer_remapped_unconditionally().to_string();
 
         interp_ok((fn_instance, lo, name, filename))
     }
diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs
index 9c659f65e50..9b30d8ce78b 100644
--- a/src/tools/miri/src/shims/native_lib/mod.rs
+++ b/src/tools/miri/src/shims/native_lib/mod.rs
@@ -198,7 +198,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut libffi_args = Vec::<CArg>::with_capacity(args.len());
         for arg in args.iter() {
             if !matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) {
-                throw_unsup_format!("only scalar argument types are support for native calls")
+                throw_unsup_format!("only scalar argument types are supported for native calls")
             }
             let imm = this.read_immediate(arg)?;
             libffi_args.push(imm_to_carg(&imm, this)?);
@@ -224,16 +224,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.expose_provenance(prov)?;
             }
         }
-
-        // Prepare all exposed memory.
-        this.prepare_exposed_for_native_call()?;
-
-        // Convert them to `libffi::high::Arg` type.
+        // Convert arguments to `libffi::high::Arg` type.
         let libffi_args = libffi_args
             .iter()
             .map(|arg| arg.arg_downcast())
             .collect::<Vec<libffi::high::Arg<'_>>>();
 
+        // Prepare all exposed memory (both previously exposed, and just newly exposed since a
+        // pointer was passed as argument).
+        this.visit_reachable_allocs(this.exposed_allocs(), |this, alloc_id, info| {
+            // If there is no data behind this pointer, skip this.
+            if !matches!(info.kind, AllocKind::LiveData) {
+                return interp_ok(());
+            }
+            // It's okay to get raw access, what we do does not correspond to any actual
+            // AM operation, it just approximates the state to account for the native call.
+            let alloc = this.get_alloc_raw(alloc_id)?;
+            // Also expose the provenance of the interpreter-level allocation, so it can
+            // be read by FFI. The `black_box` is defensive programming as LLVM likes
+            // to (incorrectly) optimize away ptr2int casts whose result is unused.
+            std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance());
+            // Expose all provenances in this allocation, since the native code can do $whatever.
+            for prov in alloc.provenance().provenances() {
+                this.expose_provenance(prov)?;
+            }
+
+            // Prepare for possible write from native code if mutable.
+            if info.mutbl.is_mut() {
+                let alloc = &mut this.get_alloc_raw_mut(alloc_id)?.0;
+                alloc.prepare_for_native_access();
+                // Also expose *mutable* provenance for the interpreter-level allocation.
+                std::hint::black_box(alloc.get_bytes_unchecked_raw_mut().expose_provenance());
+            }
+
+            interp_ok(())
+        })?;
+
         // Call the function and store output, depending on return type in the function signature.
         let (ret, maybe_memevents) =
             this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
@@ -321,7 +347,8 @@ fn imm_to_carg<'tcx>(v: &ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'
             CArg::USize(v.to_scalar().to_target_usize(cx)?.try_into().unwrap()),
         ty::RawPtr(..) => {
             let s = v.to_scalar().to_pointer(cx)?.addr();
-            // This relies on the `expose_provenance` in `prepare_for_native_call`.
+            // This relies on the `expose_provenance` in the `visit_reachable_allocs` callback
+            // above.
             CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize()))
         }
         _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty),
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
index dd2dd346231..1dc334486c3 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs
@@ -20,7 +20,7 @@ fn main() {
         let mut buf: MaybeUninit<[u8; 4]> = std::mem::MaybeUninit::uninit();
         // Read 4 bytes from a 3-byte file.
         assert_eq!(libc::read(fd, buf.as_mut_ptr().cast::<std::ffi::c_void>(), 4), 3);
-        buf.assume_init(); //~ERROR: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer
+        buf.assume_init(); //~ERROR: encountered uninitialized memory, but expected an integer
         assert_eq!(libc::close(fd), 0);
     }
     remove_file(&path).unwrap();
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
index fadb31e3a8f..83119f087ff 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/libc-read-and-uninit-premature-eof.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value at .value[3]: encountered uninitialized memory, but expected an integer
+error: Undefined Behavior: constructing invalid value at [3]: encountered uninitialized memory, but expected an integer
   --> tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs:LL:CC
    |
-LL | ...   buf.assume_init();
-   |       ^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+LL |         buf.assume_init();
+   |         ^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
index dd3246d8120..34fef6b9ee5 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs
@@ -1,11 +1,6 @@
-//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
-//@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
-//@normalize-stderr-test: "\n +at [^\n]+" -> ""
-//@error-in-other-file: aborted execution
 #![feature(never_type)]
 
 #[allow(deprecated, invalid_value)]
 fn main() {
-    let _ = unsafe { std::mem::uninitialized::<!>() };
+    let _ = unsafe { std::mem::uninitialized::<!>() }; //~ERROR: constructing invalid value
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
index 3db8a5be205..36642208afe 100644
--- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr
@@ -1,27 +1,13 @@
-
-thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
-aborted execution: attempted to instantiate uninhabited type `!`
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
-thread caused non-unwinding panic. aborting.
-error: abnormal termination: the program aborted execution
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   |
-LL | ABORT()
-   | ^ abnormal termination occurred here
-   |
-   = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
-   = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
-note: inside `main`
+error: Undefined Behavior: constructing invalid value: encountered a value of the never type `!`
   --> tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC
    |
 LL |     let _ = unsafe { std::mem::uninitialized::<!>() };
-   | ^
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
index 3d355bad626..cca2c5ae984 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs
@@ -1,10 +1,4 @@
-//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()"
-//@normalize-stderr-test: "\| +\^+" -> "| ^"
-//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
-//@normalize-stderr-test: "\n +at [^\n]+" -> ""
-//@error-in-other-file: aborted execution
-
 #[allow(deprecated, invalid_value)]
 fn main() {
-    let _ = unsafe { std::mem::zeroed::<fn()>() };
+    let _ = unsafe { std::mem::zeroed::<fn()>() }; //~ERROR: constructing invalid value
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
index a1e476328b0..53f3f8d1404 100644
--- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
@@ -1,27 +1,13 @@
-
-thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
-aborted execution: attempted to zero-initialize type `fn()`, which is invalid
-note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
-thread caused non-unwinding panic. aborting.
-error: abnormal termination: the program aborted execution
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   |
-LL | ABORT()
-   | ^ abnormal termination occurred here
-   |
-   = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
-   = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
-   = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
-note: inside `main`
+error: Undefined Behavior: constructing invalid value: encountered a null function pointer
   --> tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC
    |
 LL |     let _ = unsafe { std::mem::zeroed::<fn()>() };
-   | ^
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/validity/uninit_float.stderr b/src/tools/miri/tests/fail/validity/uninit_float.stderr
index 1b948b062e1..0c859d72764 100644
--- a/src/tools/miri/tests/fail/validity/uninit_float.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_float.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a floating point number
+error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a floating point number
   --> tests/fail/validity/uninit_float.rs:LL:CC
    |
 LL |     let _val: [f32; 1] = unsafe { std::mem::uninitialized() };
diff --git a/src/tools/miri/tests/fail/validity/uninit_integer.stderr b/src/tools/miri/tests/fail/validity/uninit_integer.stderr
index b17bdee65da..5d31e2659ee 100644
--- a/src/tools/miri/tests/fail/validity/uninit_integer.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_integer.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected an integer
+error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected an integer
   --> tests/fail/validity/uninit_integer.rs:LL:CC
    |
 LL |     let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() };
diff --git a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr
index 269af6061c2..d2e9408adbe 100644
--- a/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr
+++ b/src/tools/miri/tests/fail/validity/uninit_raw_ptr.stderr
@@ -1,4 +1,4 @@
-error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer
+error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a raw pointer
   --> tests/fail/validity/uninit_raw_ptr.rs:LL:CC
    |
 LL |     let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() };
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 7bf3bb195ee..aeae5b61b95 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -81,7 +81,7 @@ version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -92,7 +92,7 @@ checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
 dependencies = [
  "anstyle",
  "once_cell_polyfill",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -103,9 +103,9 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
 
 [[package]]
 name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
 
 [[package]]
 name = "bincode"
@@ -150,9 +150,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.18.1"
+version = "3.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
 
 [[package]]
 name = "cc"
@@ -459,12 +459,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.12"
+version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -746,9 +746,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -863,9 +863,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
 [[package]]
 name = "markup5ever"
-version = "0.16.1"
+version = "0.16.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a"
+checksum = "2e4cd8c02f18a011991a039855480c64d74291c5792fcc160d55d77dc4de4a39"
 dependencies = [
  "log",
  "tendril",
@@ -991,7 +991,7 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1060,7 +1060,7 @@ checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223"
 dependencies = [
  "bstr",
  "normpath",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1083,7 +1083,7 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -1100,9 +1100,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6"
+checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
 dependencies = [
  "memchr",
  "thiserror 2.0.12",
@@ -1111,9 +1111,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5"
+checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
 dependencies = [
  "pest",
  "pest_generator",
@@ -1121,9 +1121,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841"
+checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
 dependencies = [
  "pest",
  "pest_meta",
@@ -1134,11 +1134,10 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0"
+checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
 dependencies = [
- "once_cell",
  "pest",
  "sha2",
 ]
@@ -1315,9 +1314,9 @@ dependencies = [
 
 [[package]]
 name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
 
 [[package]]
 name = "railroad"
@@ -1403,7 +1402,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1548,9 +1547,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.103"
+version = "2.0.104"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1598,7 +1597,7 @@ dependencies = [
  "getrandom",
  "once_cell",
  "rustix",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1619,7 +1618,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed"
 dependencies = [
  "rustix",
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1894,7 +1893,7 @@ version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1962,7 +1961,16 @@ version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.2",
 ]
 
 [[package]]
@@ -1971,14 +1979,30 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
+dependencies = [
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
 ]
 
 [[package]]
@@ -1988,48 +2012,96 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[package]]
 name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[package]]
 name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[package]]
 name = "windows_i686_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[package]]
 name = "windows_x86_64_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[package]]
 name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
 name = "winnow"
 version = "0.7.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index addb0af4a54..6461f38f527 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
 use std::{env, fs};
 
 use build_helper::util::try_run;
-use compiletest::header::TestProps;
+use compiletest::directives::TestProps;
 use config::Config;
 
 mod config;
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index ff87b76aa45..9dc32f335a8 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -196,7 +196,7 @@ async function main(argv) {
         // This is more convenient that setting fields one by one.
         const args = [
             "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
-            "--enable-fail-on-js-error", "--allow-file-access-from-files",
+            "--allow-file-access-from-files",
         ];
         if (opts["debug"]) {
             debug = true;
diff --git a/src/tools/rustfmt/tests/source/let_chains.rs b/src/tools/rustfmt/tests/source/let_chains.rs
index 0c4d8aa85ea..fc2a9310569 100644
--- a/src/tools/rustfmt/tests/source/let_chains.rs
+++ b/src/tools/rustfmt/tests/source/let_chains.rs
@@ -1,3 +1,5 @@
+// rustfmt-edition: 2024
+
 fn main() {
     if let x = x && x {}
 
diff --git a/src/tools/rustfmt/tests/target/let_chains.rs b/src/tools/rustfmt/tests/target/let_chains.rs
index 204937b4cac..4fd6048d914 100644
--- a/src/tools/rustfmt/tests/target/let_chains.rs
+++ b/src/tools/rustfmt/tests/target/let_chains.rs
@@ -1,3 +1,5 @@
+// rustfmt-edition: 2024
+
 fn main() {
     if let x = x
         && x
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index 4f9a20fa9e2..2904908fd43 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -72,6 +72,8 @@ fn check_impl(
     let shell_lint = lint_args.contains(&"shell:lint") || shell_all;
     let cpp_all = lint_args.contains(&"cpp");
     let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all;
+    let spellcheck_all = lint_args.contains(&"spellcheck");
+    let spellcheck_fix = lint_args.contains(&"spellcheck:fix");
 
     let mut py_path = None;
 
@@ -224,6 +226,27 @@ fn check_impl(
         shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?;
     }
 
+    if spellcheck_all || spellcheck_fix {
+        let config_path = root_path.join("typos.toml");
+        // sync target files with .github/workflows/spellcheck.yml
+        let mut args = vec![
+            "-c",
+            config_path.as_os_str().to_str().unwrap(),
+            "./compiler",
+            "./library",
+            "./src/bootstrap",
+            "./src/librustdoc",
+        ];
+
+        if spellcheck_all {
+            eprintln!("spellcheck files");
+        } else if spellcheck_fix {
+            eprintln!("spellcheck files and fix");
+            args.push("--write-changes");
+        }
+        spellcheck_runner(&args)?;
+    }
+
     Ok(())
 }
 
@@ -491,6 +514,36 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> {
     if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) }
 }
 
+/// Check that spellchecker is installed then run it at the given path
+fn spellcheck_runner(args: &[&str]) -> Result<(), Error> {
+    // sync version with .github/workflows/spellcheck.yml
+    let expected_version = "typos-cli 1.34.0";
+    match Command::new("typos").arg("--version").output() {
+        Ok(o) => {
+            let stdout = String::from_utf8_lossy(&o.stdout);
+            if stdout.trim() != expected_version {
+                return Err(Error::Version {
+                    program: "typos",
+                    required: expected_version,
+                    installed: stdout.trim().to_string(),
+                });
+            }
+        }
+        Err(e) if e.kind() == io::ErrorKind::NotFound => {
+            return Err(Error::MissingReq(
+                "typos",
+                "spellcheck file checks",
+                // sync version with .github/workflows/spellcheck.yml
+                Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()),
+            ));
+        }
+        Err(e) => return Err(e.into()),
+    }
+
+    let status = Command::new("typos").args(args).status()?;
+    if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) }
+}
+
 /// Check git for tracked files matching an extension
 fn find_with_extension(
     root_path: &Path,
diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs
index 720f0712ee0..5e924544f0d 100644
--- a/src/tools/tidy/src/rustdoc_js.rs
+++ b/src/tools/tidy/src/rustdoc_js.rs
@@ -52,8 +52,7 @@ fn get_eslint_version() -> Option<String> {
 }
 
 pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &mut bool) {
-    let eslint_version_path =
-        src_path.join("ci/docker/host-x86_64/mingw-check-tidy/eslint.version");
+    let eslint_version_path = src_path.join("ci/docker/host-x86_64/tidy/eslint.version");
     let eslint_version = match std::fs::read_to_string(&eslint_version_path) {
         Ok(version) => version.trim().to_string(),
         Err(error) => {
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index 3e9841b179c..392ad1cee14 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -5,7 +5,8 @@
 //! # Important notes
 //!
 //! - `minicore` is **only** intended for `core` items, and the stubs should match the actual `core`
-//!   items.
+//!   items. For identical error output, any `diagnostic` attributes (e.g. `on_unimplemented`)
+//!   should also be replicated here.
 //! - Be careful of adding new features and things that are only available for a subset of targets.
 //!
 //! # References
@@ -41,12 +42,24 @@ macro_rules! impl_marker_trait {
 }
 
 #[lang = "pointee_sized"]
+#[diagnostic::on_unimplemented(
+    message = "values of type `{Self}` may or may not have a size",
+    label = "may or may not have a known size"
+)]
 pub trait PointeeSized {}
 
 #[lang = "meta_sized"]
+#[diagnostic::on_unimplemented(
+    message = "the size for values of type `{Self}` cannot be known",
+    label = "doesn't have a known size"
+)]
 pub trait MetaSized: PointeeSized {}
 
 #[lang = "sized"]
+#[diagnostic::on_unimplemented(
+    message = "the size for values of type `{Self}` cannot be known at compilation time",
+    label = "doesn't have a size known at compile-time"
+)]
 pub trait Sized: MetaSized {}
 
 #[lang = "legacy_receiver"]
@@ -64,6 +77,10 @@ pub trait BikeshedGuaranteedNoDrop {}
 pub unsafe auto trait Freeze {}
 
 #[lang = "unpin"]
+#[diagnostic::on_unimplemented(
+    note = "consider using the `pin!` macro\nconsider using `Box::pin` if you need to access the pinned value outside of the current scope",
+    message = "`{Self}` cannot be unpinned"
+)]
 pub auto trait Unpin {}
 
 impl_marker_trait!(
@@ -110,6 +127,7 @@ pub struct UnsafeCell<T: PointeeSized> {
 impl<T: PointeeSized> !Freeze for UnsafeCell<T> {}
 
 #[lang = "tuple_trait"]
+#[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")]
 pub trait Tuple {}
 
 #[rustc_builtin_macro]
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index c57ade58c30..3ac6ba3beb1 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -1,6 +1,12 @@
+//@ add-core-stubs
 //@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
 
 #![crate_type = "lib"]
+#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)]
+#![no_core]
+extern crate minicore;
+
+use minicore::*;
 
 // With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
 // without needing to pointercast, and SRoA will turn that into a `bitcast`.
@@ -14,7 +20,7 @@
 // CHECK-NEXT: ret i32 %_0
 #[no_mangle]
 pub fn f32_to_bits(x: f32) -> u32 {
-    unsafe { std::mem::transmute(x) }
+    unsafe { mem::transmute(x) }
 }
 
 // CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
@@ -22,7 +28,7 @@ pub fn f32_to_bits(x: f32) -> u32 {
 // CHECK-NEXT: ret i8 %_0
 #[no_mangle]
 pub fn bool_to_byte(b: bool) -> u8 {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
@@ -30,14 +36,14 @@ pub fn bool_to_byte(b: bool) -> u8 {
 // CHECK-NEXT: ret i1 %_0
 #[no_mangle]
 pub unsafe fn byte_to_bool(byte: u8) -> bool {
-    std::mem::transmute(byte)
+    mem::transmute(byte)
 }
 
 // CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p)
 // CHECK: ret ptr %p
 #[no_mangle]
 pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
-    unsafe { std::mem::transmute(p) }
+    unsafe { mem::transmute(p) }
 }
 
 // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p)
@@ -45,7 +51,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
 // CHECK-NEXT: ret [[USIZE]] %_0
 #[no_mangle]
 pub fn ptr_to_int(p: *mut u16) -> usize {
-    unsafe { std::mem::transmute(p) }
+    unsafe { mem::transmute(p) }
 }
 
 // CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i)
@@ -53,7 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
 // CHECK-NEXT: ret ptr %_0
 #[no_mangle]
 pub fn int_to_ptr(i: usize) -> *mut u16 {
-    unsafe { std::mem::transmute(i) }
+    unsafe { mem::transmute(i) }
 }
 
 // This is the one case where signedness matters to transmuting:
@@ -70,7 +76,7 @@ pub enum FakeBoolSigned {
 // CHECK-NEXT: ret i8 %_0
 #[no_mangle]
 pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b)
@@ -78,7 +84,7 @@ pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
 // CHECK-NEXT: ret i1 %_0
 #[no_mangle]
 pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 #[repr(u8)]
@@ -91,12 +97,41 @@ pub enum FakeBoolUnsigned {
 // CHECK: ret i1 %b
 #[no_mangle]
 pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
 }
 
 // CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b)
 // CHECK: ret i1 %b
 #[no_mangle]
 pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool {
-    unsafe { std::mem::transmute(b) }
+    unsafe { mem::transmute(b) }
+}
+
+#[repr(simd)]
+struct S([i64; 1]);
+
+// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b)
+// CHECK: bitcast <1 x i64> %b to i64
+// CHECK: ret i64
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 {
+    unsafe { mem::transmute(b) }
+}
+
+// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b)
+// CHECK: bitcast i64 %b to <1 x i64>
+// CHECK: ret <1 x i64>
+#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
+#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
+#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
+pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S {
+    unsafe { mem::transmute(b) }
 }
diff --git a/tests/coverage/branch/if-let.coverage b/tests/coverage/branch/if-let.coverage
index 9a3f0113f75..e55da7fb726 100644
--- a/tests/coverage/branch/if-let.coverage
+++ b/tests/coverage/branch/if-let.coverage
@@ -1,5 +1,5 @@
-   LL|       |#![feature(coverage_attribute, let_chains)]
-   LL|       |//@ edition: 2021
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2024
    LL|       |//@ compile-flags: -Zcoverage-options=branch
    LL|       |//@ llvm-cov-flags: --show-branches=count
    LL|       |
diff --git a/tests/coverage/branch/if-let.rs b/tests/coverage/branch/if-let.rs
index 13db00a82b1..6f88de54cda 100644
--- a/tests/coverage/branch/if-let.rs
+++ b/tests/coverage/branch/if-let.rs
@@ -1,5 +1,5 @@
-#![feature(coverage_attribute, let_chains)]
-//@ edition: 2021
+#![feature(coverage_attribute)]
+//@ edition: 2024
 //@ compile-flags: -Zcoverage-options=branch
 //@ llvm-cov-flags: --show-branches=count
 
diff --git a/tests/mir-opt/inline_var_debug_info_kept.rs b/tests/mir-opt/inline_var_debug_info_kept.rs
new file mode 100644
index 00000000000..e2f00fc6ee9
--- /dev/null
+++ b/tests/mir-opt/inline_var_debug_info_kept.rs
@@ -0,0 +1,50 @@
+//@ test-mir-pass: Inline
+//@ revisions: PRESERVE FULL NONE LIMITED
+//@ [PRESERVE]compile-flags: -O -C debuginfo=0 -Zinline-mir-preserve-debug
+//@ [FULL]compile-flags: -O -C debuginfo=2
+//@ [NONE]compile-flags: -O -C debuginfo=0
+//@ [LIMITED]compile-flags: -O -C debuginfo=1
+
+#[inline(always)]
+fn inline_fn1(arg1: i32) -> i32 {
+    let local1 = arg1 + 1;
+    let _local2 = 10;
+    arg1 + local1
+}
+
+#[inline(always)]
+fn inline_fn2(binding: i32) -> i32 {
+    {
+        let binding = inline_fn1(binding);
+        binding
+    }
+}
+
+#[inline(never)]
+fn test() -> i32 {
+    // CHECK-LABEL: fn test
+    inline_fn2(1)
+    // CHECK-LABEL: (inlined inline_fn2)
+
+    // PRESERVE: debug binding =>
+    // FULL: debug binding =>
+    // NONE-NOT: debug binding =>
+    // LIMITED-NOT: debug binding =>
+
+    // CHECK-LABEL: (inlined inline_fn1)
+
+    // PRESERVE: debug arg1 =>
+    // FULL: debug arg1 =>
+    // NONE-NOT: debug arg1 =>
+    // LIMITED-NOT: debug arg1 =>
+
+    // PRESERVE: debug local1 =>
+    // FULL: debug local1 =>
+    // NONE-NOT: debug local1 =>
+    // LIMITED-NOT: debug local1 =>
+
+    // PRESERVE: debug _local2 =>
+    // FULL: debug _local2 =>
+    // NONE-NOT: debug _local2 =>
+    // LIMITED-NOT: debug _local2 =>
+}
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index 97273ceb195..0df9cc2a659 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -129,13 +129,13 @@ define-function: ("check-line-numbers-existence", [], block {
     wait-for-local-storage-false: {"rustdoc-line-numbers": "true" }
     assert-false: ".example-line-numbers"
     // Line numbers should still be there.
-    assert-css: ("[data-nosnippet]", { "display": "inline-block"})
+    assert-css: ("[data-nosnippet]", { "display": "block"})
     // Now disabling the setting.
     click: "input#line-numbers"
     wait-for-local-storage: {"rustdoc-line-numbers": "true" }
     assert-false: ".example-line-numbers"
     // Line numbers should still be there.
-    assert-css: ("[data-nosnippet]", { "display": "inline-block"})
+    assert-css: ("[data-nosnippet]", { "display": "block"})
     // Closing settings menu.
     click: "#settings-menu"
     wait-for-css: ("#settings", {"display": "none"})
diff --git a/tests/rustdoc-gui/scrape-examples-button-focus.goml b/tests/rustdoc-gui/scrape-examples-button-focus.goml
index 12246a37661..f6e836e2360 100644
--- a/tests/rustdoc-gui/scrape-examples-button-focus.goml
+++ b/tests/rustdoc-gui/scrape-examples-button-focus.goml
@@ -5,7 +5,7 @@ go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
 // The next/prev buttons vertically scroll the code viewport between examples
 move-cursor-to: ".scraped-example-list > .scraped-example"
 wait-for: ".scraped-example-list > .scraped-example .next"
-store-value: (initialScrollTop, 250)
+store-value: (initialScrollTop, 236)
 assert-property: (".scraped-example-list > .scraped-example .rust", {
     "scrollTop": |initialScrollTop|,
 }, NEAR)
diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml
index cb2fd3052cd..0dab9c72ea9 100644
--- a/tests/rustdoc-gui/source-code-wrapping.goml
+++ b/tests/rustdoc-gui/source-code-wrapping.goml
@@ -31,17 +31,32 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html"
 click: "#settings-menu"
 wait-for: "#settings"
 
-store-size: (".example-wrap .rust code", {"width": rust_width, "height": rust_height})
-store-size: (".example-wrap .language-text code", {"width": txt_width, "height": txt_height})
+store-property: (".example-wrap .rust code", {"scrollWidth": rust_width, "scrollHeight": rust_height})
+store-property: (".example-wrap .language-text code", {"scrollWidth": txt_width, "scrollHeight": txt_height})
 call-function: ("click-code-wrapping", {"expected": "true"})
-wait-for-size-false: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
+wait-for-property-false: (
+    ".example-wrap .rust code",
+    {"scrollWidth": |rust_width|, "scrollHeight": |rust_height|},
+)
 
-store-size: (".example-wrap .rust code", {"width": new_rust_width, "height": new_rust_height})
-store-size: (".example-wrap .language-text code", {"width": new_txt_width, "height": new_txt_height})
+store-property: (
+    ".example-wrap .rust code",
+    {"scrollWidth": new_rust_width, "scrollHeight": new_rust_height},
+)
+store-property: (
+    ".example-wrap .language-text code",
+    {"scrollWidth": new_txt_width, "scrollHeight": new_txt_height},
+)
 
 assert: |rust_width| > |new_rust_width| && |rust_height| < |new_rust_height|
 assert: |txt_width| > |new_txt_width| && |txt_height| < |new_txt_height|
 
 call-function: ("click-code-wrapping", {"expected": "false"})
-wait-for-size: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
-assert-size: (".example-wrap .language-text code", {"width": |txt_width|, "height": |txt_height|})
+wait-for-property: (
+    ".example-wrap .rust code",
+    {"scrollWidth": |rust_width|, "scrollHeight": |rust_height|},
+)
+assert-property: (
+    ".example-wrap .language-text code",
+    {"scrollWidth": |txt_width|, "scrollHeight": |txt_height|},
+)
diff --git a/tests/rustdoc-json/attrs/target_feature.rs b/tests/rustdoc-json/attrs/target_feature.rs
new file mode 100644
index 00000000000..ee2b3235f72
--- /dev/null
+++ b/tests/rustdoc-json/attrs/target_feature.rs
@@ -0,0 +1,17 @@
+//@ only-x86_64
+
+//@ is "$.index[?(@.name=='test1')].attrs" '["#[target_feature(enable=\"avx\")]"]'
+#[target_feature(enable = "avx")]
+pub fn test1() {}
+
+//@ is "$.index[?(@.name=='test2')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]'
+#[target_feature(enable = "avx,avx2")]
+pub fn test2() {}
+
+//@ is "$.index[?(@.name=='test3')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]'
+#[target_feature(enable = "avx", enable = "avx2")]
+pub fn test3() {}
+
+//@ is "$.index[?(@.name=='test4')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\", enable=\"avx512f\")]"]'
+#[target_feature(enable = "avx", enable = "avx2,avx512f")]
+pub fn test4() {}
diff --git a/tests/rustdoc/attributes-re-export.rs b/tests/rustdoc/attributes-re-export.rs
new file mode 100644
index 00000000000..458826ea8a3
--- /dev/null
+++ b/tests/rustdoc/attributes-re-export.rs
@@ -0,0 +1,13 @@
+// Tests that attributes are correctly copied onto a re-exported item.
+//@ edition:2021
+#![crate_name = "re_export"]
+
+//@ has 're_export/fn.thingy2.html' '//pre[@class="rust item-decl"]' '#[no_mangle]'
+pub use thingymod::thingy as thingy2;
+
+mod thingymod {
+    #[no_mangle]
+    pub fn thingy() {
+
+    }
+}
diff --git a/tests/rustdoc/reexport/extern-135092.rs b/tests/rustdoc/reexport/extern-135092.rs
new file mode 100644
index 00000000000..fb5c71d56d5
--- /dev/null
+++ b/tests/rustdoc/reexport/extern-135092.rs
@@ -0,0 +1,26 @@
+// Test to make sure reexports of extern items are combined
+// <https://github.com/rust-lang/rust/issues/135092>
+
+#![crate_name = "foo"]
+
+mod native {
+    extern "C" {
+        /// bar.
+        pub fn bar();
+    }
+
+    /// baz.
+    pub fn baz() {}
+}
+
+//@ has 'foo/fn.bar.html'
+//@ has - '//div[@class="docblock"]' 'bar.'
+//@ has - '//div[@class="docblock"]' 'foo'
+/// foo
+pub use native::bar;
+
+//@ has 'foo/fn.baz.html'
+//@ has - '//div[@class="docblock"]' 'baz.'
+//@ has - '//div[@class="docblock"]' 'foo'
+/// foo
+pub use native::baz;
diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr
index 893382875a2..372ef71375c 100644
--- a/tests/ui/abi/bad-custom.stderr
+++ b/tests/ui/abi/bad-custom.stderr
@@ -166,7 +166,7 @@ error: functions with the "custom" ABI cannot be `async`
 LL | async unsafe extern "custom" fn no_async_fn() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async unsafe extern "custom" fn no_async_fn() {
 LL + unsafe extern "custom" fn no_async_fn() {
diff --git a/tests/ui/abi/cannot-be-coroutine.avr.stderr b/tests/ui/abi/cannot-be-coroutine.avr.stderr
index b06da0f3352..027f98c95c4 100644
--- a/tests/ui/abi/cannot-be-coroutine.avr.stderr
+++ b/tests/ui/abi/cannot-be-coroutine.avr.stderr
@@ -4,7 +4,7 @@ error: functions with the "avr-interrupt" ABI cannot be `async`
 LL | async extern "avr-interrupt" fn avr() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "avr-interrupt" fn avr() {
 LL + extern "avr-interrupt" fn avr() {
diff --git a/tests/ui/abi/cannot-be-coroutine.i686.stderr b/tests/ui/abi/cannot-be-coroutine.i686.stderr
index cbbddd087c8..8c9292b6a32 100644
--- a/tests/ui/abi/cannot-be-coroutine.i686.stderr
+++ b/tests/ui/abi/cannot-be-coroutine.i686.stderr
@@ -4,7 +4,7 @@ error: functions with the "x86-interrupt" ABI cannot be `async`
 LL | async extern "x86-interrupt" fn x86() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "x86-interrupt" fn x86() {
 LL + extern "x86-interrupt" fn x86() {
diff --git a/tests/ui/abi/cannot-be-coroutine.msp430.stderr b/tests/ui/abi/cannot-be-coroutine.msp430.stderr
index 951ce13b605..4b639cea9c1 100644
--- a/tests/ui/abi/cannot-be-coroutine.msp430.stderr
+++ b/tests/ui/abi/cannot-be-coroutine.msp430.stderr
@@ -4,7 +4,7 @@ error: functions with the "msp430-interrupt" ABI cannot be `async`
 LL | async extern "msp430-interrupt" fn msp430() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "msp430-interrupt" fn msp430() {
 LL + extern "msp430-interrupt" fn msp430() {
diff --git a/tests/ui/abi/cannot-be-coroutine.riscv32.stderr b/tests/ui/abi/cannot-be-coroutine.riscv32.stderr
index 8e3b3a2940a..1b18bc51f83 100644
--- a/tests/ui/abi/cannot-be-coroutine.riscv32.stderr
+++ b/tests/ui/abi/cannot-be-coroutine.riscv32.stderr
@@ -4,7 +4,7 @@ error: functions with the "riscv-interrupt-m" ABI cannot be `async`
 LL | async extern "riscv-interrupt-m" fn riscv_m() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "riscv-interrupt-m" fn riscv_m() {
 LL + extern "riscv-interrupt-m" fn riscv_m() {
@@ -16,7 +16,7 @@ error: functions with the "riscv-interrupt-s" ABI cannot be `async`
 LL | async extern "riscv-interrupt-s" fn riscv_s() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "riscv-interrupt-s" fn riscv_s() {
 LL + extern "riscv-interrupt-s" fn riscv_s() {
diff --git a/tests/ui/abi/cannot-be-coroutine.riscv64.stderr b/tests/ui/abi/cannot-be-coroutine.riscv64.stderr
index 8e3b3a2940a..1b18bc51f83 100644
--- a/tests/ui/abi/cannot-be-coroutine.riscv64.stderr
+++ b/tests/ui/abi/cannot-be-coroutine.riscv64.stderr
@@ -4,7 +4,7 @@ error: functions with the "riscv-interrupt-m" ABI cannot be `async`
 LL | async extern "riscv-interrupt-m" fn riscv_m() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "riscv-interrupt-m" fn riscv_m() {
 LL + extern "riscv-interrupt-m" fn riscv_m() {
@@ -16,7 +16,7 @@ error: functions with the "riscv-interrupt-s" ABI cannot be `async`
 LL | async extern "riscv-interrupt-s" fn riscv_s() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "riscv-interrupt-s" fn riscv_s() {
 LL + extern "riscv-interrupt-s" fn riscv_s() {
diff --git a/tests/ui/abi/cannot-be-coroutine.x64.stderr b/tests/ui/abi/cannot-be-coroutine.x64.stderr
index cbbddd087c8..8c9292b6a32 100644
--- a/tests/ui/abi/cannot-be-coroutine.x64.stderr
+++ b/tests/ui/abi/cannot-be-coroutine.x64.stderr
@@ -4,7 +4,7 @@ error: functions with the "x86-interrupt" ABI cannot be `async`
 LL | async extern "x86-interrupt" fn x86() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "x86-interrupt" fn x86() {
 LL + extern "x86-interrupt" fn x86() {
diff --git a/tests/ui/abi/cannot-be-coroutine.x64_win.stderr b/tests/ui/abi/cannot-be-coroutine.x64_win.stderr
index cbbddd087c8..8c9292b6a32 100644
--- a/tests/ui/abi/cannot-be-coroutine.x64_win.stderr
+++ b/tests/ui/abi/cannot-be-coroutine.x64_win.stderr
@@ -4,7 +4,7 @@ error: functions with the "x86-interrupt" ABI cannot be `async`
 LL | async extern "x86-interrupt" fn x86() {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: remove the `async` keyword from this definiton
+help: remove the `async` keyword from this definition
    |
 LL - async extern "x86-interrupt" fn x86() {
 LL + extern "x86-interrupt" fn x86() {
diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs
index c0d8de05fda..97f5d5fba98 100644
--- a/tests/ui/abi/debug.rs
+++ b/tests/ui/abi/debug.rs
@@ -1,3 +1,4 @@
+//@ add-core-stubs
 //@ normalize-stderr: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
 //@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
 //@ normalize-stderr: "(size): Size\([48] bytes\)" -> "$1: $$SOME_SIZE"
@@ -9,17 +10,26 @@
 //@ compile-flags: -O
 #![feature(rustc_attrs)]
 #![crate_type = "lib"]
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
 
 struct S(u16);
 
 #[rustc_abi(debug)]
-fn test(_x: u8) -> bool { true } //~ ERROR: fn_abi
+fn test(_x: u8) -> bool {
+    //~^ ERROR: fn_abi
+    true
+}
 
 #[rustc_abi(debug)]
 type TestFnPtr = fn(bool) -> u8; //~ ERROR: fn_abi
 
 #[rustc_abi(debug)]
-fn test_generic<T>(_x: *const T) { } //~ ERROR: fn_abi
+fn test_generic<T>(_x: *const T) {} //~ ERROR: fn_abi
 
 #[rustc_abi(debug)]
 const C: () = (); //~ ERROR: can only be applied to
@@ -31,7 +41,7 @@ impl S {
 
 impl S {
     #[rustc_abi(debug)]
-    fn assoc_test(&self) { } //~ ERROR: fn_abi
+    fn assoc_test(&self) {} //~ ERROR: fn_abi
 }
 
 #[rustc_abi(assert_eq)]
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index 8ed6dedf4d5..52351a2c260 100644
--- a/tests/ui/abi/debug.stderr
+++ b/tests/ui/abi/debug.stderr
@@ -89,9 +89,9 @@ error: fn_abi_of(test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:16:1
+  --> $DIR/debug.rs:23:1
    |
-LL | fn test(_x: u8) -> bool { true }
+LL | fn test(_x: u8) -> bool {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: fn_abi_of(TestFnPtr) = FnAbi {
@@ -185,7 +185,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:19:1
+  --> $DIR/debug.rs:29:1
    |
 LL | type TestFnPtr = fn(bool) -> u8;
    | ^^^^^^^^^^^^^^
@@ -263,13 +263,13 @@ error: fn_abi_of(test_generic) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:22:1
+  --> $DIR/debug.rs:32:1
    |
-LL | fn test_generic<T>(_x: *const T) { }
+LL | fn test_generic<T>(_x: *const T) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:25:1
+  --> $DIR/debug.rs:35:1
    |
 LL | const C: () = ();
    | ^^^^^^^^^^^
@@ -419,7 +419,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:41:1
+  --> $DIR/debug.rs:51:1
    |
 LL | type TestAbiNe = (fn(u8), fn(u32));
    | ^^^^^^^^^^^^^^
@@ -571,7 +571,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:44:1
+  --> $DIR/debug.rs:54:1
    |
 LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32]));
    | ^^^^^^^^^^^^^^^^^^^^
@@ -720,7 +720,7 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:47:1
+  --> $DIR/debug.rs:57:1
    |
 LL | type TestAbiNeFloat = (fn(f32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^^
@@ -870,13 +870,13 @@ error: ABIs are not compatible
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:51:1
+  --> $DIR/debug.rs:61:1
    |
 LL | type TestAbiNeSign = (fn(i32), fn(u32));
    | ^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/debug.rs:54:46
+  --> $DIR/debug.rs:64:46
    |
 LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
    |                                              ^^^^^^^^^^ doesn't have a size known at compile-time
@@ -885,13 +885,13 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
    = note: only the last element of a tuple may have a dynamically sized type
 
 error: unrecognized argument
-  --> $DIR/debug.rs:56:13
+  --> $DIR/debug.rs:66:13
    |
 LL | #[rustc_abi("assert_eq")]
    |             ^^^^^^^^^^^
 
 error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
-  --> $DIR/debug.rs:29:5
+  --> $DIR/debug.rs:39:5
    |
 LL |     const C: () = ();
    |     ^^^^^^^^^^^
@@ -981,9 +981,9 @@ error: fn_abi_of(assoc_test) = FnAbi {
            conv: Rust,
            can_unwind: $SOME_BOOL,
        }
-  --> $DIR/debug.rs:34:5
+  --> $DIR/debug.rs:44:5
    |
-LL |     fn assoc_test(&self) { }
+LL |     fn assoc_test(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
diff --git a/tests/ui/abi/rust-cold-works-with-rustic-args.rs b/tests/ui/abi/rust-cold-works-with-rustic-args.rs
index 57027364699..551485469d3 100644
--- a/tests/ui/abi/rust-cold-works-with-rustic-args.rs
+++ b/tests/ui/abi/rust-cold-works-with-rustic-args.rs
@@ -1,6 +1,15 @@
-//@build-pass
-//@compile-flags: -Clink-dead-code=true --crate-type lib
+//@ add-core-stubs
+//@ build-pass
+//@ compile-flags: -Clink-dead-code=true
 // We used to not handle all "rustic" ABIs in a (relatively) uniform way,
 // so we failed to fix up arguments for actually passing through the ABI...
 #![feature(rust_cold_cc)]
+#![crate_type = "lib"]
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
 pub extern "rust-cold" fn foo(_: [usize; 3]) {}
diff --git a/tests/ui/attributes/crate-type-macro-empty.rs b/tests/ui/attributes/crate-type-macro-empty.rs
index 5ff7fc002fd..217ff598f7a 100644
--- a/tests/ui/attributes/crate-type-macro-empty.rs
+++ b/tests/ui/attributes/crate-type-macro-empty.rs
@@ -2,6 +2,6 @@
 #[crate_type = foo!()]
 //~^ ERROR cannot find macro `foo` in this scope
 
-macro_rules! foo {} //~ ERROR unexpected end of macro invocation
+macro_rules! foo {} //~ ERROR macros must contain at least one rule
 
 fn main() {}
diff --git a/tests/ui/attributes/crate-type-macro-empty.stderr b/tests/ui/attributes/crate-type-macro-empty.stderr
index e48d3d95470..130fa454ca1 100644
--- a/tests/ui/attributes/crate-type-macro-empty.stderr
+++ b/tests/ui/attributes/crate-type-macro-empty.stderr
@@ -1,8 +1,8 @@
-error: unexpected end of macro invocation
+error: macros must contain at least one rule
   --> $DIR/crate-type-macro-empty.rs:5:1
    |
 LL | macro_rules! foo {}
-   | ^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: cannot find macro `foo` in this scope
   --> $DIR/crate-type-macro-empty.rs:2:16
diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs
index 64c0d223f83..dbe9c35b0a4 100644
--- a/tests/ui/attributes/malformed-attrs.rs
+++ b/tests/ui/attributes/malformed-attrs.rs
@@ -33,6 +33,7 @@
 //~^ ERROR malformed
 #[rustc_allow_const_fn_unstable]
 //~^ ERROR `rustc_allow_const_fn_unstable` expects a list of feature names
+//~| ERROR attribute should be applied to `const fn`
 #[allow_internal_unstable]
 //~^ ERROR `allow_internal_unstable` expects a list of feature names
 #[rustc_confusables]
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index bf063e8f6e5..c65eff8a550 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -1,11 +1,11 @@
 error: `cfg` is not followed by parentheses
-  --> $DIR/malformed-attrs.rs:100:1
+  --> $DIR/malformed-attrs.rs:101:1
    |
 LL | #[cfg]
    | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
 
 error: malformed `cfg_attr` attribute input
-  --> $DIR/malformed-attrs.rs:102:1
+  --> $DIR/malformed-attrs.rs:103:1
    |
 LL | #[cfg_attr]
    | ^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
    |           ++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0463]: can't find crate for `wloop`
-  --> $DIR/malformed-attrs.rs:209:1
+  --> $DIR/malformed-attrs.rs:210:1
    |
 LL | extern crate wloop;
    | ^^^^^^^^^^^^^^^^^^^ can't find crate
@@ -35,25 +35,19 @@ LL | #![windows_subsystem]
    | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![windows_subsystem = "windows|console"]`
 
 error: malformed `crate_name` attribute input
-  --> $DIR/malformed-attrs.rs:72:1
+  --> $DIR/malformed-attrs.rs:73:1
    |
 LL | #[crate_name]
    | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]`
 
-error: malformed `target_feature` attribute input
-  --> $DIR/malformed-attrs.rs:77:1
-   |
-LL | #[target_feature]
-   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
-
 error: malformed `export_stable` attribute input
-  --> $DIR/malformed-attrs.rs:79:1
+  --> $DIR/malformed-attrs.rs:80:1
    |
 LL | #[export_stable = 1]
    | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_stable]`
 
 error: malformed `coverage` attribute input
-  --> $DIR/malformed-attrs.rs:88:1
+  --> $DIR/malformed-attrs.rs:89:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -66,55 +60,55 @@ LL | #[coverage(on)]
    |           ++++
 
 error: malformed `no_sanitize` attribute input
-  --> $DIR/malformed-attrs.rs:90:1
+  --> $DIR/malformed-attrs.rs:91:1
    |
 LL | #[no_sanitize]
    | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]`
 
 error: malformed `no_implicit_prelude` attribute input
-  --> $DIR/malformed-attrs.rs:95:1
+  --> $DIR/malformed-attrs.rs:96:1
    |
 LL | #[no_implicit_prelude = 23]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[no_implicit_prelude]`
 
 error: malformed `proc_macro` attribute input
-  --> $DIR/malformed-attrs.rs:97:1
+  --> $DIR/malformed-attrs.rs:98:1
    |
 LL | #[proc_macro = 18]
    | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro]`
 
 error: malformed `instruction_set` attribute input
-  --> $DIR/malformed-attrs.rs:104:1
+  --> $DIR/malformed-attrs.rs:105:1
    |
 LL | #[instruction_set]
    | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]`
 
 error: malformed `patchable_function_entry` attribute input
-  --> $DIR/malformed-attrs.rs:106:1
+  --> $DIR/malformed-attrs.rs:107:1
    |
 LL | #[patchable_function_entry]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
 
 error: malformed `coroutine` attribute input
-  --> $DIR/malformed-attrs.rs:109:5
+  --> $DIR/malformed-attrs.rs:110:5
    |
 LL |     #[coroutine = 63] || {}
    |     ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]`
 
 error: malformed `proc_macro_attribute` attribute input
-  --> $DIR/malformed-attrs.rs:114:1
+  --> $DIR/malformed-attrs.rs:115:1
    |
 LL | #[proc_macro_attribute = 19]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_attribute]`
 
 error: malformed `proc_macro_derive` attribute input
-  --> $DIR/malformed-attrs.rs:121:1
+  --> $DIR/malformed-attrs.rs:122:1
    |
 LL | #[proc_macro_derive]
    | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
 
 error: malformed `must_not_suspend` attribute input
-  --> $DIR/malformed-attrs.rs:130:1
+  --> $DIR/malformed-attrs.rs:131:1
    |
 LL | #[must_not_suspend()]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -129,115 +123,115 @@ LL + #[must_not_suspend]
    |
 
 error: malformed `cfi_encoding` attribute input
-  --> $DIR/malformed-attrs.rs:132:1
+  --> $DIR/malformed-attrs.rs:133:1
    |
 LL | #[cfi_encoding]
    | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]`
 
 error: malformed `type_const` attribute input
-  --> $DIR/malformed-attrs.rs:141:5
+  --> $DIR/malformed-attrs.rs:142:5
    |
 LL |     #[type_const = 1]
    |     ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[type_const]`
 
 error: malformed `marker` attribute input
-  --> $DIR/malformed-attrs.rs:153:1
+  --> $DIR/malformed-attrs.rs:154:1
    |
 LL | #[marker = 3]
    | ^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
 
 error: malformed `fundamental` attribute input
-  --> $DIR/malformed-attrs.rs:155:1
+  --> $DIR/malformed-attrs.rs:156:1
    |
 LL | #[fundamental()]
    | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[fundamental]`
 
 error: malformed `ffi_pure` attribute input
-  --> $DIR/malformed-attrs.rs:163:5
+  --> $DIR/malformed-attrs.rs:164:5
    |
 LL |     #[unsafe(ffi_pure = 1)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[ffi_pure]`
 
 error: malformed `link_ordinal` attribute input
-  --> $DIR/malformed-attrs.rs:165:5
+  --> $DIR/malformed-attrs.rs:166:5
    |
 LL |     #[link_ordinal]
    |     ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_ordinal(ordinal)]`
 
 error: malformed `ffi_const` attribute input
-  --> $DIR/malformed-attrs.rs:169:5
+  --> $DIR/malformed-attrs.rs:170:5
    |
 LL |     #[unsafe(ffi_const = 1)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[ffi_const]`
 
 error: malformed `linkage` attribute input
-  --> $DIR/malformed-attrs.rs:171:5
+  --> $DIR/malformed-attrs.rs:172:5
    |
 LL |     #[linkage]
    |     ^^^^^^^^^^ help: must be of the form: `#[linkage = "external|internal|..."]`
 
 error: malformed `allow` attribute input
-  --> $DIR/malformed-attrs.rs:176:1
+  --> $DIR/malformed-attrs.rs:177:1
    |
 LL | #[allow]
    | ^^^^^^^^ help: must be of the form: `#[allow(lint1, lint2, ..., /*opt*/ reason = "...")]`
 
 error: malformed `expect` attribute input
-  --> $DIR/malformed-attrs.rs:178:1
+  --> $DIR/malformed-attrs.rs:179:1
    |
 LL | #[expect]
    | ^^^^^^^^^ help: must be of the form: `#[expect(lint1, lint2, ..., /*opt*/ reason = "...")]`
 
 error: malformed `warn` attribute input
-  --> $DIR/malformed-attrs.rs:180:1
+  --> $DIR/malformed-attrs.rs:181:1
    |
 LL | #[warn]
    | ^^^^^^^ help: must be of the form: `#[warn(lint1, lint2, ..., /*opt*/ reason = "...")]`
 
 error: malformed `deny` attribute input
-  --> $DIR/malformed-attrs.rs:182:1
+  --> $DIR/malformed-attrs.rs:183:1
    |
 LL | #[deny]
    | ^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
 
 error: malformed `forbid` attribute input
-  --> $DIR/malformed-attrs.rs:184:1
+  --> $DIR/malformed-attrs.rs:185:1
    |
 LL | #[forbid]
    | ^^^^^^^^^ help: must be of the form: `#[forbid(lint1, lint2, ..., /*opt*/ reason = "...")]`
 
 error: malformed `debugger_visualizer` attribute input
-  --> $DIR/malformed-attrs.rs:186:1
+  --> $DIR/malformed-attrs.rs:187:1
    |
 LL | #[debugger_visualizer]
    | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
 
 error: malformed `automatically_derived` attribute input
-  --> $DIR/malformed-attrs.rs:189:1
+  --> $DIR/malformed-attrs.rs:190:1
    |
 LL | #[automatically_derived = 18]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[automatically_derived]`
 
 error: malformed `non_exhaustive` attribute input
-  --> $DIR/malformed-attrs.rs:195:1
+  --> $DIR/malformed-attrs.rs:196:1
    |
 LL | #[non_exhaustive = 1]
    | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]`
 
 error: malformed `thread_local` attribute input
-  --> $DIR/malformed-attrs.rs:201:1
+  --> $DIR/malformed-attrs.rs:202:1
    |
 LL | #[thread_local()]
    | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]`
 
 error: malformed `no_link` attribute input
-  --> $DIR/malformed-attrs.rs:205:1
+  --> $DIR/malformed-attrs.rs:206:1
    |
 LL | #[no_link()]
    | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]`
 
 error: malformed `macro_use` attribute input
-  --> $DIR/malformed-attrs.rs:207:1
+  --> $DIR/malformed-attrs.rs:208:1
    |
 LL | #[macro_use = 1]
    | ^^^^^^^^^^^^^^^^
@@ -252,7 +246,7 @@ LL + #[macro_use]
    |
 
 error: malformed `macro_export` attribute input
-  --> $DIR/malformed-attrs.rs:212:1
+  --> $DIR/malformed-attrs.rs:213:1
    |
 LL | #[macro_export = 18]
    | ^^^^^^^^^^^^^^^^^^^^
@@ -267,31 +261,31 @@ LL + #[macro_export]
    |
 
 error: malformed `allow_internal_unsafe` attribute input
-  --> $DIR/malformed-attrs.rs:214:1
+  --> $DIR/malformed-attrs.rs:215:1
    |
 LL | #[allow_internal_unsafe = 1]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[allow_internal_unsafe]`
 
 error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
-  --> $DIR/malformed-attrs.rs:97:1
+  --> $DIR/malformed-attrs.rs:98:1
    |
 LL | #[proc_macro = 18]
    | ^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type
-  --> $DIR/malformed-attrs.rs:114:1
+  --> $DIR/malformed-attrs.rs:115:1
    |
 LL | #[proc_macro_attribute = 19]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
-  --> $DIR/malformed-attrs.rs:121:1
+  --> $DIR/malformed-attrs.rs:122:1
    |
 LL | #[proc_macro_derive]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint
-  --> $DIR/malformed-attrs.rs:214:1
+  --> $DIR/malformed-attrs.rs:215:1
    |
 LL | #[allow_internal_unsafe = 1]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -300,7 +294,7 @@ LL | #[allow_internal_unsafe = 1]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
-  --> $DIR/malformed-attrs.rs:42:1
+  --> $DIR/malformed-attrs.rs:43:1
    |
 LL | #[doc]
    | ^^^^^^
@@ -310,7 +304,7 @@ LL | #[doc]
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
-  --> $DIR/malformed-attrs.rs:74:1
+  --> $DIR/malformed-attrs.rs:75:1
    |
 LL | #[doc]
    | ^^^^^^
@@ -319,7 +313,7 @@ LL | #[doc]
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
 error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
-  --> $DIR/malformed-attrs.rs:81:1
+  --> $DIR/malformed-attrs.rs:82:1
    |
 LL | #[link]
    | ^^^^^^^
@@ -328,7 +322,7 @@ LL | #[link]
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
 error: valid forms for the attribute are `#[ignore]` and `#[ignore = "reason"]`
-  --> $DIR/malformed-attrs.rs:92:1
+  --> $DIR/malformed-attrs.rs:93:1
    |
 LL | #[ignore()]
    | ^^^^^^^^^^^
@@ -337,7 +331,7 @@ LL | #[ignore()]
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
 error: invalid argument
-  --> $DIR/malformed-attrs.rs:186:1
+  --> $DIR/malformed-attrs.rs:187:1
    |
 LL | #[debugger_visualizer]
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -359,13 +353,13 @@ LL | #[rustc_allow_const_fn_unstable]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `allow_internal_unstable` expects a list of feature names
-  --> $DIR/malformed-attrs.rs:36:1
+  --> $DIR/malformed-attrs.rs:37:1
    |
 LL | #[allow_internal_unstable]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0539]: malformed `rustc_confusables` attribute input
-  --> $DIR/malformed-attrs.rs:38:1
+  --> $DIR/malformed-attrs.rs:39:1
    |
 LL | #[rustc_confusables]
    | ^^^^^^^^^^^^^^^^^^^^
@@ -374,7 +368,7 @@ LL | #[rustc_confusables]
    | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]`
 
 error[E0539]: malformed `deprecated` attribute input
-  --> $DIR/malformed-attrs.rs:40:1
+  --> $DIR/malformed-attrs.rs:41:1
    |
 LL | #[deprecated = 5]
    | ^^^^^^^^^^^^^^^-^
@@ -394,13 +388,13 @@ LL + #[deprecated]
    |
 
 error[E0539]: malformed `rustc_macro_transparency` attribute input
-  --> $DIR/malformed-attrs.rs:45:1
+  --> $DIR/malformed-attrs.rs:46:1
    |
 LL | #[rustc_macro_transparency]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_macro_transparency = "transparent|semitransparent|opaque"]`
 
 error[E0539]: malformed `repr` attribute input
-  --> $DIR/malformed-attrs.rs:47:1
+  --> $DIR/malformed-attrs.rs:48:1
    |
 LL | #[repr]
    | ^^^^^^^
@@ -409,7 +403,7 @@ LL | #[repr]
    | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
 
 error[E0565]: malformed `rustc_as_ptr` attribute input
-  --> $DIR/malformed-attrs.rs:49:1
+  --> $DIR/malformed-attrs.rs:50:1
    |
 LL | #[rustc_as_ptr = 5]
    | ^^^^^^^^^^^^^^^---^
@@ -418,7 +412,7 @@ LL | #[rustc_as_ptr = 5]
    | help: must be of the form: `#[rustc_as_ptr]`
 
 error[E0539]: malformed `align` attribute input
-  --> $DIR/malformed-attrs.rs:54:1
+  --> $DIR/malformed-attrs.rs:55:1
    |
 LL | #[align]
    | ^^^^^^^^
@@ -427,7 +421,7 @@ LL | #[align]
    | help: must be of the form: `#[align(<alignment in bytes>)]`
 
 error[E0539]: malformed `optimize` attribute input
-  --> $DIR/malformed-attrs.rs:56:1
+  --> $DIR/malformed-attrs.rs:57:1
    |
 LL | #[optimize]
    | ^^^^^^^^^^^
@@ -436,7 +430,7 @@ LL | #[optimize]
    | help: must be of the form: `#[optimize(size|speed|none)]`
 
 error[E0565]: malformed `cold` attribute input
-  --> $DIR/malformed-attrs.rs:58:1
+  --> $DIR/malformed-attrs.rs:59:1
    |
 LL | #[cold = 1]
    | ^^^^^^^---^
@@ -445,13 +439,13 @@ LL | #[cold = 1]
    | help: must be of the form: `#[cold]`
 
 error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]`
-  --> $DIR/malformed-attrs.rs:60:1
+  --> $DIR/malformed-attrs.rs:61:1
    |
 LL | #[must_use()]
    | ^^^^^^^^^^^^^
 
 error[E0565]: malformed `no_mangle` attribute input
-  --> $DIR/malformed-attrs.rs:62:1
+  --> $DIR/malformed-attrs.rs:63:1
    |
 LL | #[no_mangle = 1]
    | ^^^^^^^^^^^^---^
@@ -460,7 +454,7 @@ LL | #[no_mangle = 1]
    | help: must be of the form: `#[no_mangle]`
 
 error[E0565]: malformed `naked` attribute input
-  --> $DIR/malformed-attrs.rs:64:1
+  --> $DIR/malformed-attrs.rs:65:1
    |
 LL | #[unsafe(naked())]
    | ^^^^^^^^^^^^^^--^^
@@ -469,7 +463,7 @@ LL | #[unsafe(naked())]
    | help: must be of the form: `#[naked]`
 
 error[E0565]: malformed `track_caller` attribute input
-  --> $DIR/malformed-attrs.rs:66:1
+  --> $DIR/malformed-attrs.rs:67:1
    |
 LL | #[track_caller()]
    | ^^^^^^^^^^^^^^--^
@@ -478,13 +472,13 @@ LL | #[track_caller()]
    | help: must be of the form: `#[track_caller]`
 
 error[E0539]: malformed `export_name` attribute input
-  --> $DIR/malformed-attrs.rs:68:1
+  --> $DIR/malformed-attrs.rs:69:1
    |
 LL | #[export_name()]
    | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]`
 
 error[E0805]: malformed `used` attribute input
-  --> $DIR/malformed-attrs.rs:70:1
+  --> $DIR/malformed-attrs.rs:71:1
    |
 LL | #[used()]
    | ^^^^^^--^
@@ -499,20 +493,29 @@ LL - #[used()]
 LL + #[used]
    |
 
+error[E0539]: malformed `target_feature` attribute input
+  --> $DIR/malformed-attrs.rs:78:1
+   |
+LL | #[target_feature]
+   | ^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]`
+
 error[E0539]: malformed `link_name` attribute input
-  --> $DIR/malformed-attrs.rs:84:1
+  --> $DIR/malformed-attrs.rs:85:1
    |
 LL | #[link_name]
    | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]`
 
 error[E0539]: malformed `link_section` attribute input
-  --> $DIR/malformed-attrs.rs:86:1
+  --> $DIR/malformed-attrs.rs:87:1
    |
 LL | #[link_section]
    | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
 
 error[E0539]: malformed `must_use` attribute input
-  --> $DIR/malformed-attrs.rs:117:1
+  --> $DIR/malformed-attrs.rs:118:1
    |
 LL | #[must_use = 1]
    | ^^^^^^^^^^^^^-^
@@ -529,7 +532,7 @@ LL + #[must_use]
    |
 
 error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
-  --> $DIR/malformed-attrs.rs:126:1
+  --> $DIR/malformed-attrs.rs:127:1
    |
 LL | #[rustc_layout_scalar_valid_range_start]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -538,7 +541,7 @@ LL | #[rustc_layout_scalar_valid_range_start]
    | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
 
 error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input
-  --> $DIR/malformed-attrs.rs:128:1
+  --> $DIR/malformed-attrs.rs:129:1
    |
 LL | #[rustc_layout_scalar_valid_range_end]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -546,8 +549,20 @@ LL | #[rustc_layout_scalar_valid_range_end]
    | expected this to be a list
    | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
 
+error: attribute should be applied to `const fn`
+  --> $DIR/malformed-attrs.rs:34:1
+   |
+LL |   #[rustc_allow_const_fn_unstable]
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / fn test() {
+LL | |     #[coroutine = 63] || {}
+...  |
+LL | | }
+   | |_- not a `const fn`
+
 warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
-  --> $DIR/malformed-attrs.rs:147:1
+  --> $DIR/malformed-attrs.rs:148:1
    |
 LL | #[diagnostic::do_not_recommend()]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -555,7 +570,7 @@ LL | #[diagnostic::do_not_recommend()]
    = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
 
 warning: missing options for `on_unimplemented` attribute
-  --> $DIR/malformed-attrs.rs:136:1
+  --> $DIR/malformed-attrs.rs:137:1
    |
 LL | #[diagnostic::on_unimplemented]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -563,7 +578,7 @@ LL | #[diagnostic::on_unimplemented]
    = help: at least one of the `message`, `note` and `label` options are expected
 
 warning: malformed `on_unimplemented` attribute
-  --> $DIR/malformed-attrs.rs:138:1
+  --> $DIR/malformed-attrs.rs:139:1
    |
 LL | #[diagnostic::on_unimplemented = 1]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
@@ -571,7 +586,7 @@ LL | #[diagnostic::on_unimplemented = 1]
    = help: only `message`, `note` and `label` are allowed as options
 
 error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
-  --> $DIR/malformed-attrs.rs:51:1
+  --> $DIR/malformed-attrs.rs:52:1
    |
 LL | #[inline = 5]
    | ^^^^^^^^^^^^^
@@ -580,7 +595,7 @@ LL | #[inline = 5]
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
 error[E0308]: mismatched types
-  --> $DIR/malformed-attrs.rs:109:23
+  --> $DIR/malformed-attrs.rs:110:23
    |
 LL | fn test() {
    |          - help: a return type might be missing here: `-> _`
@@ -588,9 +603,9 @@ LL |     #[coroutine = 63] || {}
    |                       ^^^^^ expected `()`, found coroutine
    |
    = note: expected unit type `()`
-              found coroutine `{coroutine@$DIR/malformed-attrs.rs:109:23: 109:25}`
+              found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}`
 
-error: aborting due to 72 previous errors; 3 warnings emitted
+error: aborting due to 73 previous errors; 3 warnings emitted
 
 Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 532c1ab13d1..2484974cdc2 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_abi = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
+   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elfv1`, `elfv2`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/drop/drop-order-comparisons-let-chains.rs b/tests/ui/drop/drop-order-comparisons-let-chains.rs
new file mode 100644
index 00000000000..5dea5e1a580
--- /dev/null
+++ b/tests/ui/drop/drop-order-comparisons-let-chains.rs
@@ -0,0 +1,145 @@
+// See drop-order-comparisons.rs
+
+//@ edition: 2024
+//@ run-pass
+
+#![feature(if_let_guard)]
+
+fn t_if_let_chains_then() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(9).is_ok()
+        && let Ok(_v) = e.ok(8)
+        && let Ok(_) = e.ok(7)
+        && let Ok(_) = e.ok(6).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(5)
+        && let Ok(_) = e.ok(4).as_ref() {
+            e.mark(3);
+        };
+    e.assert(9);
+}
+
+fn t_guard_if_let_chains_then() {
+    let e = Events::new();
+    _ = match () {
+        () if e.ok(1).is_ok()
+            && let true = e.ok(9).is_ok()
+            && let Ok(_v) = e.ok(8)
+            && let Ok(_) = e.ok(7)
+            && let Ok(_) = e.ok(6).as_ref()
+            && e.ok(2).is_ok()
+            && let Ok(_v) = e.ok(5)
+            && let Ok(_) = e.ok(4).as_ref() => {
+                e.mark(3);
+            }
+        _ => {}
+    };
+    e.assert(9);
+}
+
+fn t_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = if e.ok(1).is_ok()
+        && let true = e.ok(8).is_ok()
+        && let Ok(_v) = e.ok(7)
+        && let Ok(_) = e.ok(6)
+        && let Ok(_) = e.ok(5).as_ref()
+        && e.ok(2).is_ok()
+        && let Ok(_v) = e.ok(4)
+        && let Ok(_) = e.err(3) {} else {
+            e.mark(9);
+        };
+    e.assert(9);
+}
+
+fn t_guard_if_let_chains_then_else() {
+    let e = Events::new();
+    _ = match () {
+       () if e.ok(1).is_ok()
+            && let true = e.ok(8).is_ok()
+            && let Ok(_v) = e.ok(7)
+            && let Ok(_) = e.ok(6)
+            && let Ok(_) = e.ok(5).as_ref()
+            && e.ok(2).is_ok()
+            && let Ok(_v) = e.ok(4)
+            && let Ok(_) = e.err(3) => {}
+        _ => {
+            e.mark(9);
+        }
+    };
+    e.assert(9);
+}
+
+fn main() {
+    t_if_let_chains_then();
+    t_guard_if_let_chains_then();
+    t_if_let_chains_then_else();
+    t_guard_if_let_chains_then_else();
+}
+
+// # Test scaffolding
+
+use core::cell::RefCell;
+use std::collections::HashSet;
+
+/// A buffer to track the order of events.
+///
+/// First, numbered events are logged into this buffer.
+///
+/// Then, `assert` is called to verify that the correct number of
+/// events were logged, and that they were logged in the expected
+/// order.
+struct Events(RefCell<Option<Vec<u64>>>);
+
+impl Events {
+    const fn new() -> Self {
+        Self(RefCell::new(Some(Vec::new())))
+    }
+    #[track_caller]
+    fn assert(&self, max: u64) {
+        let buf = &self.0;
+        let v1 = buf.borrow().as_ref().unwrap().clone();
+        let mut v2 = buf.borrow().as_ref().unwrap().clone();
+        *buf.borrow_mut() = None;
+        v2.sort();
+        let uniq_len = v2.iter().collect::<HashSet<_>>().len();
+        // Check that the sequence is sorted.
+        assert_eq!(v1, v2);
+        // Check that there are no duplicates.
+        assert_eq!(v2.len(), uniq_len);
+        // Check that the length is the expected one.
+        assert_eq!(max, uniq_len as u64);
+        // Check that the last marker is the expected one.
+        assert_eq!(v2.last().unwrap(), &max);
+    }
+    /// Return an `Ok` value that logs its drop.
+    fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
+        Ok(LogDrop(self, m))
+    }
+    /// Return an `Err` value that logs its drop.
+    fn err(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
+        Err(LogDrop(self, m))
+    }
+    /// Log an event.
+    fn mark(&self, m: u64) {
+        self.0.borrow_mut().as_mut().unwrap().push(m);
+    }
+}
+
+impl Drop for Events {
+    fn drop(&mut self) {
+        if self.0.borrow().is_some() {
+            panic!("failed to call `Events::assert()`");
+        }
+    }
+}
+
+/// A type that logs its drop events.
+struct LogDrop<'b>(&'b Events, u64);
+
+impl<'b> Drop for LogDrop<'b> {
+    fn drop(&mut self) {
+        self.0.mark(self.1);
+    }
+}
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed
index 42f805923ec..b0f6eb93f70 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.fixed
+++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed
@@ -1,3 +1,6 @@
+// N.B. drop-order-comparisons-let-chains.rs is part of this test.
+// It is separate because let chains cannot be parsed before Rust 2024.
+//
 // This tests various aspects of the drop order with a focus on:
 //
 // - The lifetime of temporaries with the `if let` construct (and with
@@ -25,7 +28,6 @@
 //@ run-pass
 
 #![feature(if_let_guard)]
-#![cfg_attr(e2021, feature(let_chains))]
 #![cfg_attr(e2021, warn(rust_2024_compatibility))]
 
 fn t_bindings() {
@@ -313,59 +315,6 @@ fn t_let_else_chained_then() {
 
 #[cfg(e2021)]
 #[rustfmt::skip]
-fn t_if_let_chains_then() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(9).is_ok()
-        && let Ok(_v) = e.ok(5)
-        && let Ok(_) = e.ok(8)
-        && let Ok(_) = e.ok(7).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(4)
-        && let Ok(_) = e.ok(6).as_ref() {
-            e.mark(3);
-        };
-    e.assert(9);
-}
-
-#[cfg(e2024)]
-#[rustfmt::skip]
-fn t_if_let_chains_then() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(9).is_ok()
-        && let Ok(_v) = e.ok(8)
-        && let Ok(_) = e.ok(7)
-        && let Ok(_) = e.ok(6).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(5)
-        && let Ok(_) = e.ok(4).as_ref() {
-            e.mark(3);
-        };
-    e.assert(9);
-}
-
-#[rustfmt::skip]
-fn t_guard_if_let_chains_then() {
-    let e = Events::new();
-    _ = match () {
-        () if e.ok(1).is_ok()
-            && let true = e.ok(9).is_ok()
-            && let Ok(_v) = e.ok(8)
-            && let Ok(_) = e.ok(7)
-            && let Ok(_) = e.ok(6).as_ref()
-            && e.ok(2).is_ok()
-            && let Ok(_v) = e.ok(5)
-            && let Ok(_) = e.ok(4).as_ref() => {
-                e.mark(3);
-            }
-        _ => {}
-    };
-    e.assert(9);
-}
-
-#[cfg(e2021)]
-#[rustfmt::skip]
 fn t_if_let_nested_else() {
     let e = Events::new();
     _ = if e.err(1).is_ok() {} else {
@@ -470,59 +419,6 @@ fn t_let_else_chained_then_else() {
     e.assert(9);
 }
 
-#[cfg(e2021)]
-#[rustfmt::skip]
-fn t_if_let_chains_then_else() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(9).is_ok()
-        && let Ok(_v) = e.ok(4)
-        && let Ok(_) = e.ok(8)
-        && let Ok(_) = e.ok(7).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(3)
-        && let Ok(_) = e.err(6) {} else {
-            e.mark(5);
-        };
-    e.assert(9);
-}
-
-#[cfg(e2024)]
-#[rustfmt::skip]
-fn t_if_let_chains_then_else() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(8).is_ok()
-        && let Ok(_v) = e.ok(7)
-        && let Ok(_) = e.ok(6)
-        && let Ok(_) = e.ok(5).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(4)
-        && let Ok(_) = e.err(3) {} else {
-            e.mark(9);
-        };
-    e.assert(9);
-}
-
-#[rustfmt::skip]
-fn t_guard_if_let_chains_then_else() {
-    let e = Events::new();
-    _ = match () {
-       () if e.ok(1).is_ok()
-            && let true = e.ok(8).is_ok()
-            && let Ok(_v) = e.ok(7)
-            && let Ok(_) = e.ok(6)
-            && let Ok(_) = e.ok(5).as_ref()
-            && e.ok(2).is_ok()
-            && let Ok(_v) = e.ok(4)
-            && let Ok(_) = e.err(3) => {}
-        _ => {
-            e.mark(9);
-        }
-    };
-    e.assert(9);
-}
-
 fn main() {
     t_bindings();
     t_tuples();
@@ -540,13 +436,9 @@ fn main() {
     t_if_let_else_tailexpr();
     t_if_let_nested_then();
     t_let_else_chained_then();
-    t_if_let_chains_then();
-    t_guard_if_let_chains_then();
     t_if_let_nested_else();
     t_if_let_nested_then_else();
     t_let_else_chained_then_else();
-    t_if_let_chains_then_else();
-    t_guard_if_let_chains_then_else();
 }
 
 // # Test scaffolding
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr
index 8b93376cc0d..15a3f274514 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.stderr
+++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr
@@ -1,5 +1,5 @@
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:77:9
+  --> $DIR/drop-order-comparisons.rs:79:9
    |
 LL |       _ = ({
    |  _________-
@@ -29,35 +29,35 @@ LL | |     }, e.mark(3), e.ok(4));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#3` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `_v` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = 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/drop-order-comparisons.rs:29:25
+  --> $DIR/drop-order-comparisons.rs:31:25
    |
 LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))]
    |                         ^^^^^^^^^^^^^^^^^^^^^^^
    = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]`
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:101:45
+  --> $DIR/drop-order-comparisons.rs:103:45
    |
 LL |       _ = ({
    |  _________-
@@ -77,19 +77,19 @@ LL | |     }, e.mark(1), e.ok(4));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:101:19
+  --> $DIR/drop-order-comparisons.rs:103:19
    |
 LL |       _ = ({
    |  _________-
@@ -109,19 +109,19 @@ LL | |     }, e.mark(1), e.ok(4));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:222:24
+  --> $DIR/drop-order-comparisons.rs:224:24
    |
 LL |       _ = ({
    |  _________-
@@ -141,19 +141,19 @@ LL | |     }, e.mark(2), e.ok(3));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
-  --> $DIR/drop-order-comparisons.rs:248:24
+  --> $DIR/drop-order-comparisons.rs:250:24
    |
 LL |       _ = ({
    |  _________-
@@ -173,19 +173,19 @@ LL | |     }, e.mark(2), e.ok(3));
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
 note: `#2` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:124:13
+  --> $DIR/drop-order-comparisons.rs:126:13
    |
 LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
    |             ^^^^^^^^^^^^-------^^^^^^^^^
@@ -195,12 +195,12 @@ LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:128:5
+  --> $DIR/drop-order-comparisons.rs:130:5
    |
 LL |     }, e.mark(2), e.ok(3));
    |     ^
@@ -215,7 +215,7 @@ LL ~     } _ => {}}, e.mark(2), e.ok(3));
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:146:13
+  --> $DIR/drop-order-comparisons.rs:148:13
    |
 LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
    |             ^^^^^^^^^^^^--------^^^^^^^^^
@@ -225,12 +225,12 @@ LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:146:44
+  --> $DIR/drop-order-comparisons.rs:148:44
    |
 LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
    |                                            ^
@@ -244,7 +244,7 @@ LL ~     }}, e.mark(2), e.ok(3));
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:248:12
+  --> $DIR/drop-order-comparisons.rs:250:12
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |            ^^^^^^^^^^^^--------^^^^^^^^^
@@ -254,12 +254,12 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:248:43
+  --> $DIR/drop-order-comparisons.rs:250:43
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |                                           ^
@@ -273,7 +273,7 @@ LL ~         }}
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:372:12
+  --> $DIR/drop-order-comparisons.rs:321:12
    |
 LL |         if let true = e.err(9).is_ok() {} else {
    |            ^^^^^^^^^^^--------^^^^^^^^
@@ -283,12 +283,12 @@ LL |         if let true = e.err(9).is_ok() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:372:41
+  --> $DIR/drop-order-comparisons.rs:321:41
    |
 LL |         if let true = e.err(9).is_ok() {} else {
    |                                         ^
@@ -302,7 +302,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:375:12
+  --> $DIR/drop-order-comparisons.rs:324:12
    |
 LL |         if let Ok(_v) = e.err(8) {} else {
    |            ^^^^^^^^^^^^^--------
@@ -312,12 +312,12 @@ LL |         if let Ok(_v) = e.err(8) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:375:35
+  --> $DIR/drop-order-comparisons.rs:324:35
    |
 LL |         if let Ok(_v) = e.err(8) {} else {
    |                                   ^
@@ -331,7 +331,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:378:12
+  --> $DIR/drop-order-comparisons.rs:327:12
    |
 LL |         if let Ok(_) = e.err(7) {} else {
    |            ^^^^^^^^^^^^--------
@@ -341,12 +341,12 @@ LL |         if let Ok(_) = e.err(7) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:378:34
+  --> $DIR/drop-order-comparisons.rs:327:34
    |
 LL |         if let Ok(_) = e.err(7) {} else {
    |                                  ^
@@ -360,7 +360,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:381:12
+  --> $DIR/drop-order-comparisons.rs:330:12
    |
 LL |         if let Ok(_) = e.err(6).as_ref() {} else {
    |            ^^^^^^^^^^^^--------^^^^^^^^^
@@ -370,12 +370,12 @@ LL |         if let Ok(_) = e.err(6).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:381:43
+  --> $DIR/drop-order-comparisons.rs:330:43
    |
 LL |         if let Ok(_) = e.err(6).as_ref() {} else {
    |                                           ^
@@ -389,7 +389,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:385:12
+  --> $DIR/drop-order-comparisons.rs:334:12
    |
 LL |         if let Ok(_v) = e.err(5) {} else {
    |            ^^^^^^^^^^^^^--------
@@ -399,12 +399,12 @@ LL |         if let Ok(_v) = e.err(5) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:385:35
+  --> $DIR/drop-order-comparisons.rs:334:35
    |
 LL |         if let Ok(_v) = e.err(5) {} else {
    |                                   ^
@@ -418,7 +418,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:388:12
+  --> $DIR/drop-order-comparisons.rs:337:12
    |
 LL |         if let Ok(_) = e.err(4) {} else {
    |            ^^^^^^^^^^^^--------
@@ -428,12 +428,12 @@ LL |         if let Ok(_) = e.err(4) {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:388:34
+  --> $DIR/drop-order-comparisons.rs:337:34
    |
 LL |         if let Ok(_) = e.err(4) {} else {
    |                                  ^
@@ -447,7 +447,7 @@ LL ~         }}}}}}}}};
    |
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/drop-order-comparisons.rs:424:12
+  --> $DIR/drop-order-comparisons.rs:373:12
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |            ^^^^^^^^^^^^--------^^^^^^^^^
@@ -457,12 +457,12 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
 note: value invokes this custom destructor
-  --> $DIR/drop-order-comparisons.rs:612:1
+  --> $DIR/drop-order-comparisons.rs:504:1
    |
 LL | impl<'b> Drop for LogDrop<'b> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
-  --> $DIR/drop-order-comparisons.rs:424:43
+  --> $DIR/drop-order-comparisons.rs:373:43
    |
 LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |                                           ^
diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs
index e7425159aa2..257c0c14ecf 100644
--- a/tests/ui/drop/drop-order-comparisons.rs
+++ b/tests/ui/drop/drop-order-comparisons.rs
@@ -1,3 +1,6 @@
+// N.B. drop-order-comparisons-let-chains.rs is part of this test.
+// It is separate because let chains cannot be parsed before Rust 2024.
+//
 // This tests various aspects of the drop order with a focus on:
 //
 // - The lifetime of temporaries with the `if let` construct (and with
@@ -25,7 +28,6 @@
 //@ run-pass
 
 #![feature(if_let_guard)]
-#![cfg_attr(e2021, feature(let_chains))]
 #![cfg_attr(e2021, warn(rust_2024_compatibility))]
 
 fn t_bindings() {
@@ -313,59 +315,6 @@ fn t_let_else_chained_then() {
 
 #[cfg(e2021)]
 #[rustfmt::skip]
-fn t_if_let_chains_then() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(9).is_ok()
-        && let Ok(_v) = e.ok(5)
-        && let Ok(_) = e.ok(8)
-        && let Ok(_) = e.ok(7).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(4)
-        && let Ok(_) = e.ok(6).as_ref() {
-            e.mark(3);
-        };
-    e.assert(9);
-}
-
-#[cfg(e2024)]
-#[rustfmt::skip]
-fn t_if_let_chains_then() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(9).is_ok()
-        && let Ok(_v) = e.ok(8)
-        && let Ok(_) = e.ok(7)
-        && let Ok(_) = e.ok(6).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(5)
-        && let Ok(_) = e.ok(4).as_ref() {
-            e.mark(3);
-        };
-    e.assert(9);
-}
-
-#[rustfmt::skip]
-fn t_guard_if_let_chains_then() {
-    let e = Events::new();
-    _ = match () {
-        () if e.ok(1).is_ok()
-            && let true = e.ok(9).is_ok()
-            && let Ok(_v) = e.ok(8)
-            && let Ok(_) = e.ok(7)
-            && let Ok(_) = e.ok(6).as_ref()
-            && e.ok(2).is_ok()
-            && let Ok(_v) = e.ok(5)
-            && let Ok(_) = e.ok(4).as_ref() => {
-                e.mark(3);
-            }
-        _ => {}
-    };
-    e.assert(9);
-}
-
-#[cfg(e2021)]
-#[rustfmt::skip]
 fn t_if_let_nested_else() {
     let e = Events::new();
     _ = if e.err(1).is_ok() {} else {
@@ -470,59 +419,6 @@ fn t_let_else_chained_then_else() {
     e.assert(9);
 }
 
-#[cfg(e2021)]
-#[rustfmt::skip]
-fn t_if_let_chains_then_else() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(9).is_ok()
-        && let Ok(_v) = e.ok(4)
-        && let Ok(_) = e.ok(8)
-        && let Ok(_) = e.ok(7).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(3)
-        && let Ok(_) = e.err(6) {} else {
-            e.mark(5);
-        };
-    e.assert(9);
-}
-
-#[cfg(e2024)]
-#[rustfmt::skip]
-fn t_if_let_chains_then_else() {
-    let e = Events::new();
-    _ = if e.ok(1).is_ok()
-        && let true = e.ok(8).is_ok()
-        && let Ok(_v) = e.ok(7)
-        && let Ok(_) = e.ok(6)
-        && let Ok(_) = e.ok(5).as_ref()
-        && e.ok(2).is_ok()
-        && let Ok(_v) = e.ok(4)
-        && let Ok(_) = e.err(3) {} else {
-            e.mark(9);
-        };
-    e.assert(9);
-}
-
-#[rustfmt::skip]
-fn t_guard_if_let_chains_then_else() {
-    let e = Events::new();
-    _ = match () {
-       () if e.ok(1).is_ok()
-            && let true = e.ok(8).is_ok()
-            && let Ok(_v) = e.ok(7)
-            && let Ok(_) = e.ok(6)
-            && let Ok(_) = e.ok(5).as_ref()
-            && e.ok(2).is_ok()
-            && let Ok(_v) = e.ok(4)
-            && let Ok(_) = e.err(3) => {}
-        _ => {
-            e.mark(9);
-        }
-    };
-    e.assert(9);
-}
-
 fn main() {
     t_bindings();
     t_tuples();
@@ -540,13 +436,9 @@ fn main() {
     t_if_let_else_tailexpr();
     t_if_let_nested_then();
     t_let_else_chained_then();
-    t_if_let_chains_then();
-    t_guard_if_let_chains_then();
     t_if_let_nested_else();
     t_if_let_nested_then_else();
     t_let_else_chained_then_else();
-    t_if_let_chains_then_else();
-    t_guard_if_let_chains_then_else();
 }
 
 // # Test scaffolding
diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs
index 34b1a0e8f75..ead498a21c3 100644
--- a/tests/ui/drop/drop_order.rs
+++ b/tests/ui/drop/drop_order.rs
@@ -5,8 +5,6 @@
 //@ [edition2024] compile-flags: -Z lint-mir
 //@ [edition2024] edition: 2024
 
-#![cfg_attr(edition2021, feature(let_chains))]
-
 use std::cell::RefCell;
 use std::convert::TryInto;
 
@@ -210,68 +208,6 @@ impl DropOrderCollector {
         }
     }
 
-    fn let_chain(&self) {
-        // take the "then" branch
-        if self.option_loud_drop(1).is_some() // 1
-            && self.option_loud_drop(2).is_some() // 2
-            && let Some(_d) = self.option_loud_drop(4) { // 4
-            self.print(3); // 3
-        }
-
-        #[cfg(edition2021)]
-        // take the "else" branch
-        if self.option_loud_drop(5).is_some() // 1
-            && self.option_loud_drop(6).is_some() // 2
-            && let None = self.option_loud_drop(8) { // 4
-            unreachable!();
-        } else {
-            self.print(7); // 3
-        }
-        #[cfg(edition2024)]
-        // take the "else" branch
-        if self.option_loud_drop(5).is_some() // 1
-            && self.option_loud_drop(6).is_some() // 2
-            && let None = self.option_loud_drop(7) { // 4
-            unreachable!();
-        } else {
-            self.print(8); // 3
-        }
-
-        // let exprs interspersed
-        if self.option_loud_drop(9).is_some() // 1
-            && let Some(_d) = self.option_loud_drop(13) // 5
-            && self.option_loud_drop(10).is_some() // 2
-            && let Some(_e) = self.option_loud_drop(12) { // 4
-            self.print(11); // 3
-        }
-
-        // let exprs first
-        if let Some(_d) = self.option_loud_drop(18) // 5
-            && let Some(_e) = self.option_loud_drop(17) // 4
-            && self.option_loud_drop(14).is_some() // 1
-            && self.option_loud_drop(15).is_some() { // 2
-                self.print(16); // 3
-            }
-
-        // let exprs last
-        if self.option_loud_drop(19).is_some() // 1
-            && self.option_loud_drop(20).is_some() // 2
-            && let Some(_d) = self.option_loud_drop(23) // 5
-            && let Some(_e) = self.option_loud_drop(22) { // 4
-                self.print(21); // 3
-        }
-    }
-
-    fn while_(&self) {
-        let mut v = self.option_loud_drop(4);
-        while let Some(_d) = v
-            && self.option_loud_drop(1).is_some()
-            && self.option_loud_drop(2).is_some() {
-            self.print(3);
-            v = None;
-        }
-    }
-
     fn assert_sorted(self) {
         assert!(
             self.0
@@ -313,14 +249,4 @@ fn main() {
     let collector = DropOrderCollector::default();
     collector.match_();
     collector.assert_sorted();
-
-    println!("-- let chain --");
-    let collector = DropOrderCollector::default();
-    collector.let_chain();
-    collector.assert_sorted();
-
-    println!("-- while --");
-    let collector = DropOrderCollector::default();
-    collector.while_();
-    collector.assert_sorted();
 }
diff --git a/tests/ui/drop/drop_order_let_chain.rs b/tests/ui/drop/drop_order_let_chain.rs
new file mode 100644
index 00000000000..8d1b71c4dab
--- /dev/null
+++ b/tests/ui/drop/drop_order_let_chain.rs
@@ -0,0 +1,103 @@
+//@ run-pass
+//@ compile-flags: -Z validate-mir
+//@ edition: 2024
+
+use std::cell::RefCell;
+use std::convert::TryInto;
+
+#[derive(Default)]
+struct DropOrderCollector(RefCell<Vec<u32>>);
+
+struct LoudDrop<'a>(&'a DropOrderCollector, u32);
+
+impl Drop for LoudDrop<'_> {
+    fn drop(&mut self) {
+        println!("{}", self.1);
+        self.0.0.borrow_mut().push(self.1);
+    }
+}
+
+impl DropOrderCollector {
+    fn option_loud_drop(&self, n: u32) -> Option<LoudDrop<'_>> {
+        Some(LoudDrop(self, n))
+    }
+
+    fn print(&self, n: u32) {
+        println!("{}", n);
+        self.0.borrow_mut().push(n)
+    }
+
+    fn let_chain(&self) {
+        // take the "then" branch
+        if self.option_loud_drop(1).is_some() // 1
+            && self.option_loud_drop(2).is_some() // 2
+            && let Some(_d) = self.option_loud_drop(4) { // 4
+            self.print(3); // 3
+        }
+
+        // take the "else" branch
+        if self.option_loud_drop(5).is_some() // 1
+            && self.option_loud_drop(6).is_some() // 2
+            && let None = self.option_loud_drop(7) { // 4
+            unreachable!();
+        } else {
+            self.print(8); // 3
+        }
+
+        // let exprs interspersed
+        if self.option_loud_drop(9).is_some() // 1
+            && let Some(_d) = self.option_loud_drop(13) // 5
+            && self.option_loud_drop(10).is_some() // 2
+            && let Some(_e) = self.option_loud_drop(12) { // 4
+            self.print(11); // 3
+        }
+
+        // let exprs first
+        if let Some(_d) = self.option_loud_drop(18) // 5
+            && let Some(_e) = self.option_loud_drop(17) // 4
+            && self.option_loud_drop(14).is_some() // 1
+            && self.option_loud_drop(15).is_some() { // 2
+                self.print(16); // 3
+            }
+
+        // let exprs last
+        if self.option_loud_drop(19).is_some() // 1
+            && self.option_loud_drop(20).is_some() // 2
+            && let Some(_d) = self.option_loud_drop(23) // 5
+            && let Some(_e) = self.option_loud_drop(22) { // 4
+                self.print(21); // 3
+        }
+    }
+
+    fn while_(&self) {
+        let mut v = self.option_loud_drop(4);
+        while let Some(_d) = v
+            && self.option_loud_drop(1).is_some()
+            && self.option_loud_drop(2).is_some() {
+            self.print(3);
+            v = None;
+        }
+    }
+
+    fn assert_sorted(self) {
+        assert!(
+            self.0
+                .into_inner()
+                .into_iter()
+                .enumerate()
+                .all(|(idx, item)| idx + 1 == item.try_into().unwrap())
+        );
+    }
+}
+
+fn main() {
+    println!("-- let chain --");
+    let collector = DropOrderCollector::default();
+    collector.let_chain();
+    collector.assert_sorted();
+
+    println!("-- while --");
+    let collector = DropOrderCollector::default();
+    collector.while_();
+    collector.assert_sorted();
+}
diff --git a/tests/ui/drop/issue-100276.rs b/tests/ui/drop/issue-100276.rs
index 5d212b3a0a9..c8e25e48b15 100644
--- a/tests/ui/drop/issue-100276.rs
+++ b/tests/ui/drop/issue-100276.rs
@@ -1,11 +1,6 @@
 //@ check-pass
-//@ compile-flags: -Z validate-mir
-//@ revisions: edition2021 edition2024
-//@ [edition2021] edition: 2021
-//@ [edition2024] compile-flags: -Z lint-mir
-//@ [edition2024] edition: 2024
-
-#![cfg_attr(edition2021, feature(let_chains))]
+//@ compile-flags: -Z lint-mir -Z validate-mir
+//@ edition: 2024
 
 fn let_chains(entry: std::io::Result<std::fs::DirEntry>) {
     if let Ok(entry) = entry
diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr
index 95a5a58ab85..88c08cb94ba 100644
--- a/tests/ui/error-codes/E0637.stderr
+++ b/tests/ui/error-codes/E0637.stderr
@@ -3,6 +3,8 @@ error[E0637]: `'_` cannot be used here
    |
 LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
    |                        ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0106]: missing lifetime specifier
   --> $DIR/E0637.rs:1:62
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 02b9e2f06ee..9280dfdf92e 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -387,14 +387,6 @@ LL | #![link()]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
-   |
-LL | #![cold]
-   | ^^^^^^^^ cannot be applied to crates
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
 warning: attribute should be applied to a foreign function or static
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1
    |
@@ -417,6 +409,14 @@ warning: `#[must_use]` has no effect when applied to a module
 LL | #![must_use]
    | ^^^^^^^^^^^^
 
+warning: attribute should be applied to a function definition
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
+   |
+LL | #![cold]
+   | ^^^^^^^^ cannot be applied to crates
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5
    |
diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed
index a8c8dd1d512..be322a31363 100644
--- a/tests/ui/lint/lint-unnecessary-parens.fixed
+++ b/tests/ui/lint/lint-unnecessary-parens.fixed
@@ -1,5 +1,6 @@
 //@ run-rustfix
 
+#![feature(impl_trait_in_fn_trait_return)]
 #![deny(unused_parens)]
 #![allow(while_true)] // for rustfix
 
@@ -16,11 +17,11 @@ fn bar(y: bool) -> X {
     return X { y }; //~ ERROR unnecessary parentheses around `return` value
 }
 
-pub fn unused_parens_around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type
+pub fn around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type
     panic!()
 }
 
-pub fn unused_parens_around_block_return() -> u32 {
+pub fn around_block_return() -> u32 {
     let _foo = {
         5 //~ ERROR unnecessary parentheses around block return value
     };
@@ -31,10 +32,90 @@ pub trait Trait {
     fn test(&self);
 }
 
-pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
+pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) {
     panic!()
 }
 
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_ref() -> &'static dyn Trait {
+    panic!()
+}
+
+pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) {
+    panic!()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_ptr() -> *const dyn Trait {
+    panic!()
+}
+
+pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send {
+    &|| ()
+}
+
+pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) {
+    &|| ()
+}
+
+pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send {
+    || ()
+}
+
+pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_dyn_bound() -> &'static dyn FnOnce() {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_impl_trait_bound() -> impl FnOnce() {
+    || ()
+}
+
+// these parens aren't strictly required but they help disambiguate => no lint
+pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_regular_bound1() -> &'static (dyn Send + Sync) {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_regular_bound2() -> &'static (dyn Send + Sync) {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) {
+    &|| ()
+}
+
 pub fn parens_with_keyword(e: &[()]) -> i32 {
     if true {} //~ ERROR unnecessary parentheses around `if`
     while true {} //~ ERROR unnecessary parentheses around `while`
diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs
index 02aa78283c7..dccad07311b 100644
--- a/tests/ui/lint/lint-unnecessary-parens.rs
+++ b/tests/ui/lint/lint-unnecessary-parens.rs
@@ -1,5 +1,6 @@
 //@ run-rustfix
 
+#![feature(impl_trait_in_fn_trait_return)]
 #![deny(unused_parens)]
 #![allow(while_true)] // for rustfix
 
@@ -16,11 +17,11 @@ fn bar(y: bool) -> X {
     return (X { y }); //~ ERROR unnecessary parentheses around `return` value
 }
 
-pub fn unused_parens_around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type
+pub fn around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type
     panic!()
 }
 
-pub fn unused_parens_around_block_return() -> u32 {
+pub fn around_block_return() -> u32 {
     let _foo = {
         (5) //~ ERROR unnecessary parentheses around block return value
     };
@@ -31,10 +32,90 @@ pub trait Trait {
     fn test(&self);
 }
 
-pub fn passes_unused_parens_lint() -> &'static (dyn Trait) {
+pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) {
     panic!()
 }
 
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_ref() -> &'static (dyn Trait) {
+    panic!()
+}
+
+pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) {
+    panic!()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_ptr() -> *const (dyn Trait) {
+    panic!()
+}
+
+pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) {
+    &|| ()
+}
+
+pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) {
+    &|| ()
+}
+
+pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) {
+    || ()
+}
+
+pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_dyn_bound() -> &'static dyn (FnOnce()) {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_impl_trait_bound() -> impl (FnOnce()) {
+    || ()
+}
+
+// these parens aren't strictly required but they help disambiguate => no lint
+pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) {
+    || ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) {
+    &|| ()
+}
+
+//~v ERROR unnecessary parentheses around type
+pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) {
+    &|| ()
+}
+
 pub fn parens_with_keyword(e: &[()]) -> i32 {
     if(true) {} //~ ERROR unnecessary parentheses around `if`
     while(true) {} //~ ERROR unnecessary parentheses around `while`
diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr
index f2e5debd6e0..a7fc1e89c6c 100644
--- a/tests/ui/lint/lint-unnecessary-parens.stderr
+++ b/tests/ui/lint/lint-unnecessary-parens.stderr
@@ -1,11 +1,11 @@
 error: unnecessary parentheses around `return` value
-  --> $DIR/lint-unnecessary-parens.rs:13:12
+  --> $DIR/lint-unnecessary-parens.rs:14:12
    |
 LL |     return (1);
    |            ^ ^
    |
 note: the lint level is defined here
-  --> $DIR/lint-unnecessary-parens.rs:3:9
+  --> $DIR/lint-unnecessary-parens.rs:4:9
    |
 LL | #![deny(unused_parens)]
    |         ^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL +     return 1;
    |
 
 error: unnecessary parentheses around `return` value
-  --> $DIR/lint-unnecessary-parens.rs:16:12
+  --> $DIR/lint-unnecessary-parens.rs:17:12
    |
 LL |     return (X { y });
    |            ^       ^
@@ -28,19 +28,19 @@ LL +     return X { y };
    |
 
 error: unnecessary parentheses around type
-  --> $DIR/lint-unnecessary-parens.rs:19:46
+  --> $DIR/lint-unnecessary-parens.rs:20:32
    |
-LL | pub fn unused_parens_around_return_type() -> (u32) {
-   |                                              ^   ^
+LL | pub fn around_return_type() -> (u32) {
+   |                                ^   ^
    |
 help: remove these parentheses
    |
-LL - pub fn unused_parens_around_return_type() -> (u32) {
-LL + pub fn unused_parens_around_return_type() -> u32 {
+LL - pub fn around_return_type() -> (u32) {
+LL + pub fn around_return_type() -> u32 {
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:25:9
+  --> $DIR/lint-unnecessary-parens.rs:26:9
    |
 LL |         (5)
    |         ^ ^
@@ -52,7 +52,7 @@ LL +         5
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:27:5
+  --> $DIR/lint-unnecessary-parens.rs:28:5
    |
 LL |     (5)
    |     ^ ^
@@ -63,8 +63,140 @@ LL -     (5)
 LL +     5
    |
 
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:40:46
+   |
+LL | pub fn around_single_bound_ref() -> &'static (dyn Trait) {
+   |                                              ^         ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_single_bound_ref() -> &'static (dyn Trait) {
+LL + pub fn around_single_bound_ref() -> &'static dyn Trait {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:49:44
+   |
+LL | pub fn around_single_bound_ptr() -> *const (dyn Trait) {
+   |                                            ^         ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_single_bound_ptr() -> *const (dyn Trait) {
+LL + pub fn around_single_bound_ptr() -> *const dyn Trait {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:58:72
+   |
+LL | pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) {
+   |                                                                        ^         ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) {
+LL + pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:71:65
+   |
+LL | pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) {
+   |                                                                 ^         ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) {
+LL + pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:80:43
+   |
+LL | pub fn around_dyn_bound() -> &'static dyn (FnOnce()) {
+   |                                           ^        ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_dyn_bound() -> &'static dyn (FnOnce()) {
+LL + pub fn around_dyn_bound() -> &'static dyn FnOnce() {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:85:42
+   |
+LL | pub fn around_impl_trait_bound() -> impl (FnOnce()) {
+   |                                          ^        ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_impl_trait_bound() -> impl (FnOnce()) {
+LL + pub fn around_impl_trait_bound() -> impl FnOnce() {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:95:55
+   |
+LL | pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send {
+   |                                                       ^    ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send {
+LL + pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:100:67
+   |
+LL | pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) {
+   |                                                                   ^          ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) {
+LL + pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:105:49
+   |
+LL | pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) {
+   |                                                 ^    ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) {
+LL + pub fn around_regular_bound1() -> &'static (dyn Send + Sync) {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:110:56
+   |
+LL | pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) {
+   |                                                        ^    ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) {
+LL + pub fn around_regular_bound2() -> &'static (dyn Send + Sync) {
+   |
+
+error: unnecessary parentheses around type
+  --> $DIR/lint-unnecessary-parens.rs:115:56
+   |
+LL | pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) {
+   |                                                        ^                   ^
+   |
+help: remove these parentheses
+   |
+LL - pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) {
+LL + pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) {
+   |
+
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:39:7
+  --> $DIR/lint-unnecessary-parens.rs:120:7
    |
 LL |     if(true) {}
    |       ^    ^
@@ -76,7 +208,7 @@ LL +     if true {}
    |
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:40:10
+  --> $DIR/lint-unnecessary-parens.rs:121:10
    |
 LL |     while(true) {}
    |          ^    ^
@@ -88,7 +220,7 @@ LL +     while true {}
    |
 
 error: unnecessary parentheses around `for` iterator expression
-  --> $DIR/lint-unnecessary-parens.rs:41:13
+  --> $DIR/lint-unnecessary-parens.rs:122:13
    |
 LL |     for _ in(e) {}
    |             ^ ^
@@ -100,7 +232,7 @@ LL +     for _ in e {}
    |
 
 error: unnecessary parentheses around `match` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:42:10
+  --> $DIR/lint-unnecessary-parens.rs:123:10
    |
 LL |     match(1) { _ => ()}
    |          ^ ^
@@ -112,7 +244,7 @@ LL +     match 1 { _ => ()}
    |
 
 error: unnecessary parentheses around `return` value
-  --> $DIR/lint-unnecessary-parens.rs:43:11
+  --> $DIR/lint-unnecessary-parens.rs:124:11
    |
 LL |     return(1);
    |           ^ ^
@@ -124,7 +256,7 @@ LL +     return 1;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:74:31
+  --> $DIR/lint-unnecessary-parens.rs:155:31
    |
 LL | pub const CONST_ITEM: usize = (10);
    |                               ^  ^
@@ -136,7 +268,7 @@ LL + pub const CONST_ITEM: usize = 10;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:75:33
+  --> $DIR/lint-unnecessary-parens.rs:156:33
    |
 LL | pub static STATIC_ITEM: usize = (10);
    |                                 ^  ^
@@ -148,7 +280,7 @@ LL + pub static STATIC_ITEM: usize = 10;
    |
 
 error: unnecessary parentheses around function argument
-  --> $DIR/lint-unnecessary-parens.rs:79:9
+  --> $DIR/lint-unnecessary-parens.rs:160:9
    |
 LL |     bar((true));
    |         ^    ^
@@ -160,7 +292,7 @@ LL +     bar(true);
    |
 
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:81:8
+  --> $DIR/lint-unnecessary-parens.rs:162:8
    |
 LL |     if (true) {}
    |        ^    ^
@@ -172,7 +304,7 @@ LL +     if true {}
    |
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:82:11
+  --> $DIR/lint-unnecessary-parens.rs:163:11
    |
 LL |     while (true) {}
    |           ^    ^
@@ -184,7 +316,7 @@ LL +     while true {}
    |
 
 error: unnecessary parentheses around `match` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:83:11
+  --> $DIR/lint-unnecessary-parens.rs:164:11
    |
 LL |     match (true) {
    |           ^    ^
@@ -196,7 +328,7 @@ LL +     match true {
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:86:16
+  --> $DIR/lint-unnecessary-parens.rs:167:16
    |
 LL |     if let 1 = (1) {}
    |                ^ ^
@@ -208,7 +340,7 @@ LL +     if let 1 = 1 {}
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:87:19
+  --> $DIR/lint-unnecessary-parens.rs:168:19
    |
 LL |     while let 1 = (2) {}
    |                   ^ ^
@@ -220,7 +352,7 @@ LL +     while let 1 = 2 {}
    |
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:103:24
+  --> $DIR/lint-unnecessary-parens.rs:184:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^    ^
@@ -232,7 +364,7 @@ LL +     X { y: false }.foo(true);
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:105:18
+  --> $DIR/lint-unnecessary-parens.rs:186:18
    |
 LL |     let mut _a = (0);
    |                  ^ ^
@@ -244,7 +376,7 @@ LL +     let mut _a = 0;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:106:10
+  --> $DIR/lint-unnecessary-parens.rs:187:10
    |
 LL |     _a = (0);
    |          ^ ^
@@ -256,7 +388,7 @@ LL +     _a = 0;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:107:11
+  --> $DIR/lint-unnecessary-parens.rs:188:11
    |
 LL |     _a += (1);
    |           ^ ^
@@ -268,7 +400,7 @@ LL +     _a += 1;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:109:8
+  --> $DIR/lint-unnecessary-parens.rs:190:8
    |
 LL |     let(mut _a) = 3;
    |        ^      ^
@@ -280,7 +412,7 @@ LL +     let mut _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:110:9
+  --> $DIR/lint-unnecessary-parens.rs:191:9
    |
 LL |     let (mut _a) = 3;
    |         ^      ^
@@ -292,7 +424,7 @@ LL +     let mut _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:111:8
+  --> $DIR/lint-unnecessary-parens.rs:192:8
    |
 LL |     let( mut _a) = 3;
    |        ^^      ^
@@ -304,7 +436,7 @@ LL +     let mut _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:113:8
+  --> $DIR/lint-unnecessary-parens.rs:194:8
    |
 LL |     let(_a) = 3;
    |        ^  ^
@@ -316,7 +448,7 @@ LL +     let _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:114:9
+  --> $DIR/lint-unnecessary-parens.rs:195:9
    |
 LL |     let (_a) = 3;
    |         ^  ^
@@ -328,7 +460,7 @@ LL +     let _a = 3;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:115:8
+  --> $DIR/lint-unnecessary-parens.rs:196:8
    |
 LL |     let( _a) = 3;
    |        ^^  ^
@@ -340,7 +472,7 @@ LL +     let _a = 3;
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:121:9
+  --> $DIR/lint-unnecessary-parens.rs:202:9
    |
 LL |         (unit!() - One)
    |         ^             ^
@@ -352,7 +484,7 @@ LL +         unit!() - One
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:123:9
+  --> $DIR/lint-unnecessary-parens.rs:204:9
    |
 LL |         (unit![] - One)
    |         ^             ^
@@ -364,7 +496,7 @@ LL +         unit![] - One
    |
 
 error: unnecessary parentheses around block return value
-  --> $DIR/lint-unnecessary-parens.rs:126:9
+  --> $DIR/lint-unnecessary-parens.rs:207:9
    |
 LL |         (unit! {} - One)
    |         ^              ^
@@ -376,7 +508,7 @@ LL +         unit! {} - One
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:131:14
+  --> $DIR/lint-unnecessary-parens.rs:212:14
    |
 LL |     let _r = (&x);
    |              ^  ^
@@ -388,7 +520,7 @@ LL +     let _r = &x;
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:132:14
+  --> $DIR/lint-unnecessary-parens.rs:213:14
    |
 LL |     let _r = (&mut x);
    |              ^      ^
@@ -399,5 +531,5 @@ LL -     let _r = (&mut x);
 LL +     let _r = &mut x;
    |
 
-error: aborting due to 33 previous errors
+error: aborting due to 44 previous errors
 
diff --git a/tests/ui/lint/unused/issue-105061-should-lint.rs b/tests/ui/lint/unused/issue-105061-should-lint.rs
index 433c2882089..74a0ff83739 100644
--- a/tests/ui/lint/unused/issue-105061-should-lint.rs
+++ b/tests/ui/lint/unused/issue-105061-should-lint.rs
@@ -14,7 +14,7 @@ where
 trait Hello<T> {}
 fn with_dyn_bound<T>()
 where
-    (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T> //~ ERROR unnecessary parentheses around type
+    dyn Hello<(for<'b> fn(&'b ()))>: Hello<T> //~ ERROR unnecessary parentheses around type
 {}
 
 fn main() {
diff --git a/tests/ui/lint/unused/issue-105061-should-lint.stderr b/tests/ui/lint/unused/issue-105061-should-lint.stderr
index e591f1ffb6b..ae69f018eae 100644
--- a/tests/ui/lint/unused/issue-105061-should-lint.stderr
+++ b/tests/ui/lint/unused/issue-105061-should-lint.stderr
@@ -17,15 +17,15 @@ LL +     for<'b> for<'a> fn(Inv<'a>): Trait<'b>,
    |
 
 error: unnecessary parentheses around type
-  --> $DIR/issue-105061-should-lint.rs:17:16
+  --> $DIR/issue-105061-should-lint.rs:17:15
    |
-LL |     (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T>
-   |                ^                  ^
+LL |     dyn Hello<(for<'b> fn(&'b ()))>: Hello<T>
+   |               ^                  ^
    |
 help: remove these parentheses
    |
-LL -     (dyn Hello<(for<'b> fn(&'b ()))>): Hello<T>
-LL +     (dyn Hello<for<'b> fn(&'b ())>): Hello<T>
+LL -     dyn Hello<(for<'b> fn(&'b ()))>: Hello<T>
+LL +     dyn Hello<for<'b> fn(&'b ())>: Hello<T>
    |
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed
new file mode 100644
index 00000000000..f95418868e1
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed
@@ -0,0 +1,27 @@
+//@ revisions: edition2015 edition2018
+//@[edition2015] check-pass
+//@[edition2015] edition: 2015
+//@[edition2018] run-rustfix
+//@[edition2018] edition: 2018
+
+#![deny(unused_parens)]
+
+#[allow(unused)]
+macro_rules! edition2015_only {
+    () => {
+        mod dyn {
+            pub type IsAContextualKeywordIn2015 = ();
+        }
+
+        pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015;
+    }
+}
+
+#[cfg(edition2015)]
+edition2015_only!();
+
+// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015
+//[edition2018]~v ERROR unnecessary parentheses around type
+pub type DynIsAContextualKeywordIn2015B = Box<dyn ::std::ops::Fn()>;
+
+fn main() {}
diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr
new file mode 100644
index 00000000000..aed8cec68e8
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr
@@ -0,0 +1,19 @@
+error: unnecessary parentheses around type
+  --> $DIR/unused-parens-trait-obj.rs:25:51
+   |
+LL | pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>;
+   |                                                   ^                ^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-parens-trait-obj.rs:7:9
+   |
+LL | #![deny(unused_parens)]
+   |         ^^^^^^^^^^^^^
+help: remove these parentheses
+   |
+LL - pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>;
+LL + pub type DynIsAContextualKeywordIn2015B = Box<dyn ::std::ops::Fn()>;
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.rs b/tests/ui/lint/unused/unused-parens-trait-obj.rs
new file mode 100644
index 00000000000..2192baa2e02
--- /dev/null
+++ b/tests/ui/lint/unused/unused-parens-trait-obj.rs
@@ -0,0 +1,27 @@
+//@ revisions: edition2015 edition2018
+//@[edition2015] check-pass
+//@[edition2015] edition: 2015
+//@[edition2018] run-rustfix
+//@[edition2018] edition: 2018
+
+#![deny(unused_parens)]
+
+#[allow(unused)]
+macro_rules! edition2015_only {
+    () => {
+        mod dyn {
+            pub type IsAContextualKeywordIn2015 = ();
+        }
+
+        pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015;
+    }
+}
+
+#[cfg(edition2015)]
+edition2015_only!();
+
+// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015
+//[edition2018]~v ERROR unnecessary parentheses around type
+pub type DynIsAContextualKeywordIn2015B = Box<dyn (::std::ops::Fn())>;
+
+fn main() {}
diff --git a/tests/ui/loop-match/invalid.rs b/tests/ui/loop-match/invalid.rs
index 2ddc19f4fc6..0c47b1e0057 100644
--- a/tests/ui/loop-match/invalid.rs
+++ b/tests/ui/loop-match/invalid.rs
@@ -159,3 +159,34 @@ fn arm_has_guard(cond: bool) {
         }
     }
 }
+
+fn non_exhaustive() {
+    let mut state = State::A;
+    #[loop_match]
+    loop {
+        state = 'blk: {
+            match state {
+                //~^ ERROR non-exhaustive patterns: `State::B` and `State::C` not covered
+                State::A => State::B,
+            }
+        }
+    }
+}
+
+fn invalid_range_pattern(state: f32) {
+    #[loop_match]
+    loop {
+        state = 'blk: {
+            match state {
+                1.0 => {
+                    #[const_continue]
+                    break 'blk 2.5;
+                }
+                4.0..3.0 => {
+                    //~^ ERROR lower range bound must be less than upper
+                    todo!()
+                }
+            }
+        }
+    }
+}
diff --git a/tests/ui/loop-match/invalid.stderr b/tests/ui/loop-match/invalid.stderr
index 51fdd024c6f..70f246caa9c 100644
--- a/tests/ui/loop-match/invalid.stderr
+++ b/tests/ui/loop-match/invalid.stderr
@@ -86,6 +86,36 @@ error: match arms that are part of a `#[loop_match]` cannot have guards
 LL |                 State::B if cond => break 'a,
    |                             ^^^^
 
-error: aborting due to 12 previous errors
+error[E0004]: non-exhaustive patterns: `State::B` and `State::C` not covered
+  --> $DIR/invalid.rs:168:19
+   |
+LL |             match state {
+   |                   ^^^^^ patterns `State::B` and `State::C` not covered
+   |
+note: `State` defined here
+  --> $DIR/invalid.rs:7:6
+   |
+LL | enum State {
+   |      ^^^^^
+LL |     A,
+LL |     B,
+   |     - not covered
+LL |     C,
+   |     - not covered
+   = note: the matched value is of type `State`
+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 ~                 State::A => State::B,
+LL ~                 State::B | State::C => todo!(),
+   |
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/invalid.rs:185:17
+   |
+LL |                 4.0..3.0 => {
+   |                 ^^^^^^^^
+
+error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0004, E0308, E0579.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/macros/missing-semi.stderr b/tests/ui/macros/missing-semi.stderr
index 0a7afe50059..c2e12adbb4b 100644
--- a/tests/ui/macros/missing-semi.stderr
+++ b/tests/ui/macros/missing-semi.stderr
@@ -1,8 +1,10 @@
 error: expected `;`, found `(`
   --> $DIR/missing-semi.rs:6:5
    |
+LL |     }
+   |      - expected `;`
 LL |     () => {
-   |     ^ no rules expected this token in macro call
+   |     ^ unexpected token
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
index c858051a7eb..fa06da5cbfb 100644
--- a/tests/ui/macros/stringify.rs
+++ b/tests/ui/macros/stringify.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-//@ edition:2021
+//@ edition:2024
 //@ compile-flags: --test
 
 #![allow(incomplete_features)]
@@ -10,7 +10,6 @@
 #![feature(decl_macro)]
 #![feature(explicit_tail_calls)]
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 #![feature(more_qualified_paths)]
 #![feature(never_patterns)]
 #![feature(trait_alias)]
diff --git a/tests/ui/mir/enum/negative_discr_break.rs b/tests/ui/mir/enum/negative_discr_break.rs
new file mode 100644
index 00000000000..fa1284f72a0
--- /dev/null
+++ b/tests/ui/mir/enum/negative_discr_break.rs
@@ -0,0 +1,14 @@
+//@ run-fail
+//@ compile-flags: -C debug-assertions
+//@ error-pattern: trying to construct an enum from an invalid value 0xfd
+
+#[allow(dead_code)]
+enum Foo {
+    A = -2,
+    B = -1,
+    C = 1,
+}
+
+fn main() {
+    let _val: Foo = unsafe { std::mem::transmute::<i8, Foo>(-3) };
+}
diff --git a/tests/ui/mir/enum/negative_discr_ok.rs b/tests/ui/mir/enum/negative_discr_ok.rs
new file mode 100644
index 00000000000..5c15b33fa84
--- /dev/null
+++ b/tests/ui/mir/enum/negative_discr_ok.rs
@@ -0,0 +1,53 @@
+//@ run-pass
+//@ compile-flags: -C debug-assertions
+
+#[allow(dead_code)]
+#[derive(Debug, PartialEq)]
+enum Foo {
+    A = -12121,
+    B = -2,
+    C = -1,
+    D = 1,
+    E = 2,
+    F = 12121,
+}
+
+#[allow(dead_code)]
+#[repr(i64)]
+#[derive(Debug, PartialEq)]
+enum Bar {
+    A = i64::MIN,
+    B = -2,
+    C = -1,
+    D = 1,
+    E = 2,
+    F = i64::MAX,
+}
+
+fn main() {
+    let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(-12121) };
+    assert_eq!(val, Foo::A);
+    let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(-2) };
+    assert_eq!(val, Foo::B);
+    let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(-1) };
+    assert_eq!(val, Foo::C);
+    let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(1) };
+    assert_eq!(val, Foo::D);
+    let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(2) };
+    assert_eq!(val, Foo::E);
+    let val: Foo = unsafe { std::mem::transmute::<i16, Foo>(12121) };
+    assert_eq!(val, Foo::F);
+
+    let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(i64::MIN) };
+    assert_eq!(val, Bar::A);
+    let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(-2) };
+    assert_eq!(val, Bar::B);
+    let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(-1) };
+    assert_eq!(val, Bar::C);
+    let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(1) };
+    assert_eq!(val, Bar::D);
+    let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(2) };
+    assert_eq!(val, Bar::E);
+    let val: Bar = unsafe { std::mem::transmute::<i64, Bar>(i64::MAX) };
+    assert_eq!(val, Bar::F);
+}
diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs
index 4794f3427dd..8a54f21b57f 100644
--- a/tests/ui/mir/mir_let_chains_drop_order.rs
+++ b/tests/ui/mir/mir_let_chains_drop_order.rs
@@ -1,12 +1,9 @@
 //@ run-pass
 //@ needs-unwind
-//@ revisions: edition2021 edition2024
-//@ [edition2021] edition: 2021
-//@ [edition2024] edition: 2024
+//@ edition: 2024
 
 // See `mir_drop_order.rs` for more information
 
-#![cfg_attr(edition2021, feature(let_chains))]
 #![allow(irrefutable_let_patterns)]
 
 use std::cell::RefCell;
@@ -64,9 +61,6 @@ fn main() {
                 d(10, None)
             },
         );
-        #[cfg(edition2021)]
-        assert_eq!(get(), vec![8, 7, 1, 3, 2]);
-        #[cfg(edition2024)]
         assert_eq!(get(), vec![3, 2, 8, 7, 1]);
     }
     assert_eq!(get(), vec![0, 4, 6, 9, 5]);
@@ -101,8 +95,5 @@ fn main() {
             panic::panic_any(InjectedFailure),
         );
     });
-    #[cfg(edition2021)]
-    assert_eq!(get(), vec![20, 17, 15, 11, 19, 18, 16, 12, 14, 13]);
-    #[cfg(edition2024)]
     assert_eq!(get(), vec![14, 13, 19, 18, 20, 17, 15, 11, 16, 12]);
 }
diff --git a/tests/ui/parser/issues/issue-7970b.rs b/tests/ui/parser/issues/issue-7970b.rs
index 1c4abce3959..ae06aff7cef 100644
--- a/tests/ui/parser/issues/issue-7970b.rs
+++ b/tests/ui/parser/issues/issue-7970b.rs
@@ -1,4 +1,4 @@
 fn main() {}
 
 macro_rules! test {}
-//~^ ERROR unexpected end of macro invocation
+//~^ ERROR macros must contain at least one rule
diff --git a/tests/ui/parser/issues/issue-7970b.stderr b/tests/ui/parser/issues/issue-7970b.stderr
index b23b09e752c..4715eb07c6d 100644
--- a/tests/ui/parser/issues/issue-7970b.stderr
+++ b/tests/ui/parser/issues/issue-7970b.stderr
@@ -1,8 +1,8 @@
-error: unexpected end of macro invocation
+error: macros must contain at least one rule
   --> $DIR/issue-7970b.rs:3:1
    |
 LL | macro_rules! test {}
-   | ^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/macros-no-semicolon-items.rs b/tests/ui/parser/macros-no-semicolon-items.rs
index 3afc275d61a..86889279cea 100644
--- a/tests/ui/parser/macros-no-semicolon-items.rs
+++ b/tests/ui/parser/macros-no-semicolon-items.rs
@@ -1,5 +1,5 @@
 macro_rules! foo()  //~ ERROR semicolon
-                    //~| ERROR unexpected end of macro
+                    //~| ERROR macros must contain at least one rule
 
 macro_rules! bar {
     ($($tokens:tt)*) => {}
diff --git a/tests/ui/parser/macros-no-semicolon-items.stderr b/tests/ui/parser/macros-no-semicolon-items.stderr
index 07fa2439df5..f8f3ed83688 100644
--- a/tests/ui/parser/macros-no-semicolon-items.stderr
+++ b/tests/ui/parser/macros-no-semicolon-items.stderr
@@ -38,11 +38,11 @@ help: add a semicolon
 LL | );
    |  +
 
-error: unexpected end of macro invocation
+error: macros must contain at least one rule
   --> $DIR/macros-no-semicolon-items.rs:1:1
    |
 LL | macro_rules! foo()
-   | ^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments
+   | ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.rs b/tests/ui/pattern/usefulness/conflicting_bindings.rs
index 16737e0a894..883ce4333ca 100644
--- a/tests/ui/pattern/usefulness/conflicting_bindings.rs
+++ b/tests/ui/pattern/usefulness/conflicting_bindings.rs
@@ -1,4 +1,6 @@
-#![feature(if_let_guard, let_chains)]
+//@ edition: 2024
+
+#![feature(if_let_guard)]
 
 fn main() {
     let mut x = Some(String::new());
diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.stderr b/tests/ui/pattern/usefulness/conflicting_bindings.stderr
index 6f6504e6f64..7ab3393c8d1 100644
--- a/tests/ui/pattern/usefulness/conflicting_bindings.stderr
+++ b/tests/ui/pattern/usefulness/conflicting_bindings.stderr
@@ -1,5 +1,5 @@
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:5:9
+  --> $DIR/conflicting_bindings.rs:7:9
    |
 LL |     let ref mut y @ ref mut z = x;
    |         ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -7,7 +7,7 @@ LL |     let ref mut y @ ref mut z = x;
    |         value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:7:14
+  --> $DIR/conflicting_bindings.rs:9:14
    |
 LL |     let Some(ref mut y @ ref mut z) = x else { return };
    |              ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -15,7 +15,7 @@ LL |     let Some(ref mut y @ ref mut z) = x else { return };
    |              value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:9:17
+  --> $DIR/conflicting_bindings.rs:11:17
    |
 LL |     if let Some(ref mut y @ ref mut z) = x {}
    |                 ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -23,7 +23,7 @@ LL |     if let Some(ref mut y @ ref mut z) = x {}
    |                 value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:11:17
+  --> $DIR/conflicting_bindings.rs:13:17
    |
 LL |     if let Some(ref mut y @ ref mut z) = x && true {}
    |                 ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -31,7 +31,7 @@ LL |     if let Some(ref mut y @ ref mut z) = x && true {}
    |                 value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:13:43
+  --> $DIR/conflicting_bindings.rs:15:43
    |
 LL |     if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && true {}
    |                                           ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -39,7 +39,7 @@ LL |     if let Some(_) = Some(()) && let Some(ref mut y @ ref mut z) = x && tru
    |                                           value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:15:20
+  --> $DIR/conflicting_bindings.rs:17:20
    |
 LL |     while let Some(ref mut y @ ref mut z) = x {}
    |                    ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -47,7 +47,7 @@ LL |     while let Some(ref mut y @ ref mut z) = x {}
    |                    value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:17:20
+  --> $DIR/conflicting_bindings.rs:19:20
    |
 LL |     while let Some(ref mut y @ ref mut z) = x && true {}
    |                    ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -55,7 +55,7 @@ LL |     while let Some(ref mut y @ ref mut z) = x && true {}
    |                    value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:20:9
+  --> $DIR/conflicting_bindings.rs:22:9
    |
 LL |         ref mut y @ ref mut z => {}
    |         ^^^^^^^^^   --------- value is mutably borrowed by `z` here
@@ -63,7 +63,7 @@ LL |         ref mut y @ ref mut z => {}
    |         value is mutably borrowed by `y` here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/conflicting_bindings.rs:23:24
+  --> $DIR/conflicting_bindings.rs:25:24
    |
 LL |         () if let Some(ref mut y @ ref mut z) = x => {}
    |                        ^^^^^^^^^   --------- value is mutably borrowed by `z` here
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope-let-chains.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope-let-chains.rs
new file mode 100644
index 00000000000..4d2eac2ea2d
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope-let-chains.rs
@@ -0,0 +1,57 @@
+// Ensure that temporaries in if-let guards live for the arm
+// regression test for #118593
+
+//@ check-pass
+//@ edition: 2024
+
+#![feature(if_let_guard)]
+
+fn get_temp() -> Option<String> {
+    None
+}
+
+fn let_let_chain_guard(num: u8) {
+    match num {
+        5 | 6
+            if let Some(ref a) = get_temp()
+                && let Some(ref b) = get_temp() =>
+        {
+            let _x = a;
+            let _y = b;
+        }
+        _ => {}
+    }
+    match num {
+        7 | 8
+            if let Some(ref mut c) = get_temp()
+                && let Some(ref mut d) = get_temp() =>
+        {
+            let _w = c;
+            let _z = d;
+        }
+        _ => {}
+    }
+}
+
+fn let_cond_chain_guard(num: u8) {
+    match num {
+        9 | 10
+            if let Some(ref a) = get_temp()
+                && true =>
+        {
+            let _x = a;
+        }
+        _ => {}
+    }
+    match num {
+        11 | 12
+            if let Some(ref mut b) = get_temp()
+                && true =>
+        {
+            let _w = b;
+        }
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs
index 0578b827a47..59e33bb6af8 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs
@@ -4,7 +4,6 @@
 //@ check-pass
 
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 
 fn get_temp() -> Option<String> {
     None
@@ -25,48 +24,4 @@ fn let_guard(num: u8) {
     }
 }
 
-fn let_let_chain_guard(num: u8) {
-    match num {
-        5 | 6
-            if let Some(ref a) = get_temp()
-                && let Some(ref b) = get_temp() =>
-        {
-            let _x = a;
-            let _y = b;
-        }
-        _ => {}
-    }
-    match num {
-        7 | 8
-            if let Some(ref mut c) = get_temp()
-                && let Some(ref mut d) = get_temp() =>
-        {
-            let _w = c;
-            let _z = d;
-        }
-        _ => {}
-    }
-}
-
-fn let_cond_chain_guard(num: u8) {
-    match num {
-        9 | 10
-            if let Some(ref a) = get_temp()
-                && true =>
-        {
-            let _x = a;
-        }
-        _ => {}
-    }
-    match num {
-        11 | 12
-            if let Some(ref mut b) = get_temp()
-                && true =>
-        {
-            let _w = b;
-        }
-        _ => {}
-    }
-}
-
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs
index e836b0b88ff..294a0d02770 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/partially-macro-expanded.rs
@@ -2,7 +2,6 @@
 //@ check-pass
 
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 
 macro_rules! m {
     (pattern $i:ident) => { Some($i) };
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs
index 56a6fb5bfa3..47cc7a64bd1 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs
@@ -3,7 +3,6 @@
 //@run-pass
 
 #![feature(if_let_guard)]
-#![feature(let_chains)]
 #![allow(irrefutable_let_patterns)]
 
 fn lhs_let(opt: Option<bool>) {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr
index dda09de4c53..15e7be8c65f 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr
@@ -1,239 +1,263 @@
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:36:11
+  --> $DIR/disallowed-positions.rs:35:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:36:11
+  --> $DIR/disallowed-positions.rs:35:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:39:9
+  --> $DIR/disallowed-positions.rs:38:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:39:9
+  --> $DIR/disallowed-positions.rs:38:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:42:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:42:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:9
+  --> $DIR/disallowed-positions.rs:44:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:9
+  --> $DIR/disallowed-positions.rs:44:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:24
+  --> $DIR/disallowed-positions.rs:44:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:24
+  --> $DIR/disallowed-positions.rs:44:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
 
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:48:8
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |        ^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:48:21
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                     ^^^^^^^^^
+
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:48
+  --> $DIR/disallowed-positions.rs:48:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:61
+  --> $DIR/disallowed-positions.rs:48:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:58:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:58:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:62:14
+  --> $DIR/disallowed-positions.rs:61:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:62:14
+  --> $DIR/disallowed-positions.rs:61:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:68:20
+  --> $DIR/disallowed-positions.rs:67:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:68:20
+  --> $DIR/disallowed-positions.rs:67:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:71:12
+  --> $DIR/disallowed-positions.rs:70:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:71:12
+  --> $DIR/disallowed-positions.rs:70:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:71:27
+  --> $DIR/disallowed-positions.rs:70:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:71:27
+  --> $DIR/disallowed-positions.rs:70:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:74:11
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |           ^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:74:24
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                        ^^^^^^^^^
+
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:51
+  --> $DIR/disallowed-positions.rs:74:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:64
+  --> $DIR/disallowed-positions.rs:74:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:103:9
+  --> $DIR/disallowed-positions.rs:102:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -241,7 +265,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:106:9
+  --> $DIR/disallowed-positions.rs:105:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -249,7 +273,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:108:9
+  --> $DIR/disallowed-positions.rs:107:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -257,7 +281,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:110:9
+  --> $DIR/disallowed-positions.rs:109:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -265,7 +289,7 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:118:9
+  --> $DIR/disallowed-positions.rs:117:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -273,13 +297,13 @@ LL |     if (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `||` operators are not supported in let chain conditions
-  --> $DIR/disallowed-positions.rs:121:13
+  --> $DIR/disallowed-positions.rs:120:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:123:17
+  --> $DIR/disallowed-positions.rs:122:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -287,7 +311,7 @@ LL |     if (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:125:25
+  --> $DIR/disallowed-positions.rs:124:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -295,7 +319,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:127:25
+  --> $DIR/disallowed-positions.rs:126:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -303,7 +327,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:131:12
+  --> $DIR/disallowed-positions.rs:130:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
@@ -311,7 +335,7 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:134:15
+  --> $DIR/disallowed-positions.rs:133:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -319,7 +343,7 @@ LL |     if true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:137:11
+  --> $DIR/disallowed-positions.rs:136:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -327,7 +351,7 @@ LL |     if ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:139:9
+  --> $DIR/disallowed-positions.rs:138:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -335,7 +359,7 @@ LL |     if (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:143:8
+  --> $DIR/disallowed-positions.rs:142:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -343,7 +367,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:146:8
+  --> $DIR/disallowed-positions.rs:145:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -351,7 +375,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:152:8
+  --> $DIR/disallowed-positions.rs:151:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -359,7 +383,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:158:8
+  --> $DIR/disallowed-positions.rs:157:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +391,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:162:19
+  --> $DIR/disallowed-positions.rs:161:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
@@ -375,7 +399,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:165:15
+  --> $DIR/disallowed-positions.rs:164:15
    |
 LL |     if return let 0 = 0 {}
    |               ^^^
@@ -383,7 +407,7 @@ LL |     if return let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:168:21
+  --> $DIR/disallowed-positions.rs:167:21
    |
 LL |     loop { if break let 0 = 0 {} }
    |                     ^^^
@@ -391,7 +415,7 @@ LL |     loop { if break let 0 = 0 {} }
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:171:15
+  --> $DIR/disallowed-positions.rs:170:15
    |
 LL |     if (match let 0 = 0 { _ => { false } }) {}
    |               ^^^
@@ -399,7 +423,7 @@ LL |     if (match let 0 = 0 { _ => { false } }) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:174:9
+  --> $DIR/disallowed-positions.rs:173:9
    |
 LL |     if (let 0 = 0, false).1 {}
    |         ^^^^^^^^^
@@ -407,7 +431,7 @@ LL |     if (let 0 = 0, false).1 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:177:9
+  --> $DIR/disallowed-positions.rs:176:9
    |
 LL |     if (let 0 = 0,) {}
    |         ^^^^^^^^^
@@ -415,7 +439,7 @@ LL |     if (let 0 = 0,) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:181:13
+  --> $DIR/disallowed-positions.rs:180:13
    |
 LL |         if (let 0 = 0).await {}
    |             ^^^^^^^^^
@@ -423,7 +447,7 @@ LL |         if (let 0 = 0).await {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:185:12
+  --> $DIR/disallowed-positions.rs:184:12
    |
 LL |     if (|| let 0 = 0) {}
    |            ^^^
@@ -431,7 +455,7 @@ LL |     if (|| let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:188:9
+  --> $DIR/disallowed-positions.rs:187:9
    |
 LL |     if (let 0 = 0)() {}
    |         ^^^^^^^^^
@@ -439,7 +463,7 @@ LL |     if (let 0 = 0)() {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:194:12
+  --> $DIR/disallowed-positions.rs:193:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -447,7 +471,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:197:12
+  --> $DIR/disallowed-positions.rs:196:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -455,7 +479,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:199:12
+  --> $DIR/disallowed-positions.rs:198:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -463,7 +487,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:201:12
+  --> $DIR/disallowed-positions.rs:200:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -471,7 +495,7 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:209:12
+  --> $DIR/disallowed-positions.rs:208:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -479,13 +503,13 @@ LL |     while (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `||` operators are not supported in let chain conditions
-  --> $DIR/disallowed-positions.rs:212:16
+  --> $DIR/disallowed-positions.rs:211:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:214:20
+  --> $DIR/disallowed-positions.rs:213:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -493,7 +517,7 @@ LL |     while (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:216:28
+  --> $DIR/disallowed-positions.rs:215:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -501,7 +525,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:218:28
+  --> $DIR/disallowed-positions.rs:217:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -509,7 +533,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:222:15
+  --> $DIR/disallowed-positions.rs:221:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
@@ -517,7 +541,7 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:225:18
+  --> $DIR/disallowed-positions.rs:224:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -525,7 +549,7 @@ LL |     while true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:228:14
+  --> $DIR/disallowed-positions.rs:227:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -533,7 +557,7 @@ LL |     while ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:230:12
+  --> $DIR/disallowed-positions.rs:229:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -541,7 +565,7 @@ LL |     while (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:234:11
+  --> $DIR/disallowed-positions.rs:233:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -549,7 +573,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:237:11
+  --> $DIR/disallowed-positions.rs:236:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -557,7 +581,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:243:11
+  --> $DIR/disallowed-positions.rs:242:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -565,7 +589,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:249:11
+  --> $DIR/disallowed-positions.rs:248:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -573,7 +597,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:253:22
+  --> $DIR/disallowed-positions.rs:252:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
@@ -581,7 +605,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:256:18
+  --> $DIR/disallowed-positions.rs:255:18
    |
 LL |     while return let 0 = 0 {}
    |                  ^^^
@@ -589,7 +613,7 @@ LL |     while return let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:259:39
+  --> $DIR/disallowed-positions.rs:258:39
    |
 LL |     'outer: loop { while break 'outer let 0 = 0 {} }
    |                                       ^^^
@@ -597,7 +621,7 @@ LL |     'outer: loop { while break 'outer let 0 = 0 {} }
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:262:18
+  --> $DIR/disallowed-positions.rs:261:18
    |
 LL |     while (match let 0 = 0 { _ => { false } }) {}
    |                  ^^^
@@ -605,7 +629,7 @@ LL |     while (match let 0 = 0 { _ => { false } }) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:265:12
+  --> $DIR/disallowed-positions.rs:264:12
    |
 LL |     while (let 0 = 0, false).1 {}
    |            ^^^^^^^^^
@@ -613,7 +637,7 @@ LL |     while (let 0 = 0, false).1 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:268:12
+  --> $DIR/disallowed-positions.rs:267:12
    |
 LL |     while (let 0 = 0,) {}
    |            ^^^^^^^^^
@@ -621,7 +645,7 @@ LL |     while (let 0 = 0,) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:272:16
+  --> $DIR/disallowed-positions.rs:271:16
    |
 LL |         while (let 0 = 0).await {}
    |                ^^^^^^^^^
@@ -629,7 +653,7 @@ LL |         while (let 0 = 0).await {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:276:15
+  --> $DIR/disallowed-positions.rs:275:15
    |
 LL |     while (|| let 0 = 0) {}
    |               ^^^
@@ -637,7 +661,7 @@ LL |     while (|| let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:279:12
+  --> $DIR/disallowed-positions.rs:278:12
    |
 LL |     while (let 0 = 0)() {}
    |            ^^^^^^^^^
@@ -645,7 +669,7 @@ LL |     while (let 0 = 0)() {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:296:6
+  --> $DIR/disallowed-positions.rs:295:6
    |
 LL |     &let 0 = 0;
    |      ^^^
@@ -653,7 +677,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:299:6
+  --> $DIR/disallowed-positions.rs:298:6
    |
 LL |     !let 0 = 0;
    |      ^^^
@@ -661,7 +685,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:301:6
+  --> $DIR/disallowed-positions.rs:300:6
    |
 LL |     *let 0 = 0;
    |      ^^^
@@ -669,7 +693,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:303:6
+  --> $DIR/disallowed-positions.rs:302:6
    |
 LL |     -let 0 = 0;
    |      ^^^
@@ -677,7 +701,7 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:305:13
+  --> $DIR/disallowed-positions.rs:304:13
    |
 LL |     let _ = let _ = 3;
    |             ^^^
@@ -685,7 +709,7 @@ LL |     let _ = let _ = 3;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:313:6
+  --> $DIR/disallowed-positions.rs:312:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
@@ -693,7 +717,7 @@ LL |     (let 0 = 0)?;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:316:13
+  --> $DIR/disallowed-positions.rs:315:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
@@ -701,7 +725,7 @@ LL |     true || let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:318:14
+  --> $DIR/disallowed-positions.rs:317:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
@@ -709,7 +733,7 @@ LL |     (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:320:22
+  --> $DIR/disallowed-positions.rs:319:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
@@ -717,7 +741,7 @@ LL |     true && (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:324:9
+  --> $DIR/disallowed-positions.rs:323:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
@@ -725,7 +749,7 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:327:12
+  --> $DIR/disallowed-positions.rs:326:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
@@ -733,7 +757,7 @@ LL |     true..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:329:8
+  --> $DIR/disallowed-positions.rs:328:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
@@ -741,7 +765,7 @@ LL |     ..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:331:6
+  --> $DIR/disallowed-positions.rs:330:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
@@ -749,7 +773,7 @@ LL |     (let 0 = 0)..;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:334:6
+  --> $DIR/disallowed-positions.rs:333:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
@@ -757,7 +781,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:338:6
+  --> $DIR/disallowed-positions.rs:337:6
    |
 LL |     (let true = let true = true);
    |      ^^^
@@ -765,7 +789,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:338:17
+  --> $DIR/disallowed-positions.rs:337:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
@@ -773,7 +797,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:344:25
+  --> $DIR/disallowed-positions.rs:343:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
@@ -781,7 +805,7 @@ LL |         let x = true && let y = 1;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:350:19
+  --> $DIR/disallowed-positions.rs:349:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
@@ -789,7 +813,7 @@ LL |         [1, 2, 3][let _ = ()]
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:355:6
+  --> $DIR/disallowed-positions.rs:354:6
    |
 LL |     &let 0 = 0
    |      ^^^
@@ -797,7 +821,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:366:17
+  --> $DIR/disallowed-positions.rs:365:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -805,7 +829,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:371:17
+  --> $DIR/disallowed-positions.rs:370:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -813,7 +837,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:376:17
+  --> $DIR/disallowed-positions.rs:375:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -821,7 +845,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:387:17
+  --> $DIR/disallowed-positions.rs:386:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -829,7 +853,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:387:9
+  --> $DIR/disallowed-positions.rs:386:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -840,124 +864,154 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:397:9
+  --> $DIR/disallowed-positions.rs:396:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:397:9
+  --> $DIR/disallowed-positions.rs:396:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:401:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:401:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:404:9
+  --> $DIR/disallowed-positions.rs:403:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:404:9
+  --> $DIR/disallowed-positions.rs:403:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:404:32
+  --> $DIR/disallowed-positions.rs:403:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:404:32
+  --> $DIR/disallowed-positions.rs:403:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:407:8
+   |
+LL |     if let Some(a) = opt && (true && true) {
+   |        ^^^^^^^^^^^^^^^^^
+
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:412:9
+  --> $DIR/disallowed-positions.rs:411:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:412:9
+  --> $DIR/disallowed-positions.rs:411:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:412:31
+  --> $DIR/disallowed-positions.rs:411:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:412:31
+  --> $DIR/disallowed-positions.rs:411:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:416:9
+  --> $DIR/disallowed-positions.rs:415:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:416:9
+  --> $DIR/disallowed-positions.rs:415:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:416:31
+  --> $DIR/disallowed-positions.rs:415:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:416:31
+  --> $DIR/disallowed-positions.rs:415:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:420:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:420:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:423:28
+   |
+LL |     if (true && (true)) && let Some(a) = opt {
+   |                            ^^^^^^^^^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:426:18
+   |
+LL |     if (true) && let Some(a) = opt {
+   |                  ^^^^^^^^^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:429:16
+   |
+LL |     if true && let Some(a) = opt {
+   |                ^^^^^^^^^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/disallowed-positions.rs:434:8
+   |
+LL |     if let true = (true && fun()) && (true) {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:440:22
+  --> $DIR/disallowed-positions.rs:439:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
@@ -965,7 +1019,7 @@ LL |     let x = (true && let y = 1);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:445:20
+  --> $DIR/disallowed-positions.rs:444:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
@@ -973,7 +1027,7 @@ LL |         ([1, 2, 3][let _ = ()])
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:91:16
+  --> $DIR/disallowed-positions.rs:90:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -981,7 +1035,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:91:16
+  --> $DIR/disallowed-positions.rs:90:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -990,7 +1044,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:91:16
+  --> $DIR/disallowed-positions.rs:90:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -999,7 +1053,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:95:16
+  --> $DIR/disallowed-positions.rs:94:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -1007,7 +1061,7 @@ LL |     use_expr!((let 0 = 1));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:95:16
+  --> $DIR/disallowed-positions.rs:94:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -1016,7 +1070,7 @@ LL |     use_expr!((let 0 = 1));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:95:16
+  --> $DIR/disallowed-positions.rs:94:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -1024,98 +1078,8 @@ LL |     use_expr!((let 0 = 1));
    = note: only supported directly in conditions of `if` and `while` expressions
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:49:8
-   |
-LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |        ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:49:21
-   |
-LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                     ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:75:11
-   |
-LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |           ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:75:24
-   |
-LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                        ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:408:8
-   |
-LL |     if let Some(a) = opt && (true && true) {
-   |        ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:424:28
-   |
-LL |     if (true && (true)) && let Some(a) = opt {
-   |                            ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:427:18
-   |
-LL |     if (true) && let Some(a) = opt {
-   |                  ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:430:16
-   |
-LL |     if true && let Some(a) = opt {
-   |                ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/disallowed-positions.rs:435:8
-   |
-LL |     if let true = (true && fun()) && (true) {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` 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[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:134:8
+  --> $DIR/disallowed-positions.rs:133:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -1124,7 +1088,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:143:12
+  --> $DIR/disallowed-positions.rs:142:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1135,7 +1099,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:146:12
+  --> $DIR/disallowed-positions.rs:145:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1146,7 +1110,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:152:12
+  --> $DIR/disallowed-positions.rs:151:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1157,7 +1121,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:158:12
+  --> $DIR/disallowed-positions.rs:157:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1168,7 +1132,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:114:20
+  --> $DIR/disallowed-positions.rs:113:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1176,7 +1140,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:225:11
+  --> $DIR/disallowed-positions.rs:224:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -1185,7 +1149,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:234:15
+  --> $DIR/disallowed-positions.rs:233:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1196,7 +1160,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:237:15
+  --> $DIR/disallowed-positions.rs:236:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1207,7 +1171,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:243:15
+  --> $DIR/disallowed-positions.rs:242:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1218,7 +1182,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:249:15
+  --> $DIR/disallowed-positions.rs:248:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1229,7 +1193,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:205:23
+  --> $DIR/disallowed-positions.rs:204:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1237,7 +1201,7 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:334:10
+  --> $DIR/disallowed-positions.rs:333:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1248,7 +1212,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:309:17
+  --> $DIR/disallowed-positions.rs:308:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1257,5 +1221,5 @@ LL |         let 0 = 0?;
 
 error: aborting due to 134 previous errors
 
-Some errors have detailed explanations: E0277, E0308, E0658.
+Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr
index 141a6d255d0..20af65cf89a 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr
@@ -1,239 +1,239 @@
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:36:11
+  --> $DIR/disallowed-positions.rs:35:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:36:11
+  --> $DIR/disallowed-positions.rs:35:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:39:9
+  --> $DIR/disallowed-positions.rs:38:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:39:9
+  --> $DIR/disallowed-positions.rs:38:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:42:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:42:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:9
+  --> $DIR/disallowed-positions.rs:44:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:9
+  --> $DIR/disallowed-positions.rs:44:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:24
+  --> $DIR/disallowed-positions.rs:44:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:24
+  --> $DIR/disallowed-positions.rs:44:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:48
+  --> $DIR/disallowed-positions.rs:48:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:61
+  --> $DIR/disallowed-positions.rs:48:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:58:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:58:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:62:14
+  --> $DIR/disallowed-positions.rs:61:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:62:14
+  --> $DIR/disallowed-positions.rs:61:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:68:20
+  --> $DIR/disallowed-positions.rs:67:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:68:20
+  --> $DIR/disallowed-positions.rs:67:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:71:12
+  --> $DIR/disallowed-positions.rs:70:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:71:12
+  --> $DIR/disallowed-positions.rs:70:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:71:27
+  --> $DIR/disallowed-positions.rs:70:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:71:27
+  --> $DIR/disallowed-positions.rs:70:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:51
+  --> $DIR/disallowed-positions.rs:74:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:64
+  --> $DIR/disallowed-positions.rs:74:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:103:9
+  --> $DIR/disallowed-positions.rs:102:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -241,7 +241,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:106:9
+  --> $DIR/disallowed-positions.rs:105:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -249,7 +249,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:108:9
+  --> $DIR/disallowed-positions.rs:107:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -257,7 +257,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:110:9
+  --> $DIR/disallowed-positions.rs:109:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -265,7 +265,7 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:118:9
+  --> $DIR/disallowed-positions.rs:117:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -273,13 +273,13 @@ LL |     if (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `||` operators are not supported in let chain conditions
-  --> $DIR/disallowed-positions.rs:121:13
+  --> $DIR/disallowed-positions.rs:120:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:123:17
+  --> $DIR/disallowed-positions.rs:122:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -287,7 +287,7 @@ LL |     if (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:125:25
+  --> $DIR/disallowed-positions.rs:124:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -295,7 +295,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:127:25
+  --> $DIR/disallowed-positions.rs:126:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -303,7 +303,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:131:12
+  --> $DIR/disallowed-positions.rs:130:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
@@ -311,7 +311,7 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:134:15
+  --> $DIR/disallowed-positions.rs:133:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -319,7 +319,7 @@ LL |     if true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:137:11
+  --> $DIR/disallowed-positions.rs:136:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -327,7 +327,7 @@ LL |     if ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:139:9
+  --> $DIR/disallowed-positions.rs:138:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -335,7 +335,7 @@ LL |     if (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:143:8
+  --> $DIR/disallowed-positions.rs:142:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -343,7 +343,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:146:8
+  --> $DIR/disallowed-positions.rs:145:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -351,7 +351,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:152:8
+  --> $DIR/disallowed-positions.rs:151:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -359,7 +359,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:158:8
+  --> $DIR/disallowed-positions.rs:157:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +367,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:162:19
+  --> $DIR/disallowed-positions.rs:161:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
@@ -375,7 +375,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:165:15
+  --> $DIR/disallowed-positions.rs:164:15
    |
 LL |     if return let 0 = 0 {}
    |               ^^^
@@ -383,7 +383,7 @@ LL |     if return let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:168:21
+  --> $DIR/disallowed-positions.rs:167:21
    |
 LL |     loop { if break let 0 = 0 {} }
    |                     ^^^
@@ -391,7 +391,7 @@ LL |     loop { if break let 0 = 0 {} }
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:171:15
+  --> $DIR/disallowed-positions.rs:170:15
    |
 LL |     if (match let 0 = 0 { _ => { false } }) {}
    |               ^^^
@@ -399,7 +399,7 @@ LL |     if (match let 0 = 0 { _ => { false } }) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:174:9
+  --> $DIR/disallowed-positions.rs:173:9
    |
 LL |     if (let 0 = 0, false).1 {}
    |         ^^^^^^^^^
@@ -407,7 +407,7 @@ LL |     if (let 0 = 0, false).1 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:177:9
+  --> $DIR/disallowed-positions.rs:176:9
    |
 LL |     if (let 0 = 0,) {}
    |         ^^^^^^^^^
@@ -415,7 +415,7 @@ LL |     if (let 0 = 0,) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:181:13
+  --> $DIR/disallowed-positions.rs:180:13
    |
 LL |         if (let 0 = 0).await {}
    |             ^^^^^^^^^
@@ -423,7 +423,7 @@ LL |         if (let 0 = 0).await {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:185:12
+  --> $DIR/disallowed-positions.rs:184:12
    |
 LL |     if (|| let 0 = 0) {}
    |            ^^^
@@ -431,7 +431,7 @@ LL |     if (|| let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:188:9
+  --> $DIR/disallowed-positions.rs:187:9
    |
 LL |     if (let 0 = 0)() {}
    |         ^^^^^^^^^
@@ -439,7 +439,7 @@ LL |     if (let 0 = 0)() {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:194:12
+  --> $DIR/disallowed-positions.rs:193:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -447,7 +447,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:197:12
+  --> $DIR/disallowed-positions.rs:196:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -455,7 +455,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:199:12
+  --> $DIR/disallowed-positions.rs:198:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -463,7 +463,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:201:12
+  --> $DIR/disallowed-positions.rs:200:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -471,7 +471,7 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:209:12
+  --> $DIR/disallowed-positions.rs:208:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -479,13 +479,13 @@ LL |     while (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `||` operators are not supported in let chain conditions
-  --> $DIR/disallowed-positions.rs:212:16
+  --> $DIR/disallowed-positions.rs:211:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:214:20
+  --> $DIR/disallowed-positions.rs:213:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -493,7 +493,7 @@ LL |     while (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:216:28
+  --> $DIR/disallowed-positions.rs:215:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -501,7 +501,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:218:28
+  --> $DIR/disallowed-positions.rs:217:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -509,7 +509,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:222:15
+  --> $DIR/disallowed-positions.rs:221:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
@@ -517,7 +517,7 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:225:18
+  --> $DIR/disallowed-positions.rs:224:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -525,7 +525,7 @@ LL |     while true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:228:14
+  --> $DIR/disallowed-positions.rs:227:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -533,7 +533,7 @@ LL |     while ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:230:12
+  --> $DIR/disallowed-positions.rs:229:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -541,7 +541,7 @@ LL |     while (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:234:11
+  --> $DIR/disallowed-positions.rs:233:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -549,7 +549,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:237:11
+  --> $DIR/disallowed-positions.rs:236:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -557,7 +557,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:243:11
+  --> $DIR/disallowed-positions.rs:242:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -565,7 +565,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:249:11
+  --> $DIR/disallowed-positions.rs:248:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -573,7 +573,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:253:22
+  --> $DIR/disallowed-positions.rs:252:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
@@ -581,7 +581,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:256:18
+  --> $DIR/disallowed-positions.rs:255:18
    |
 LL |     while return let 0 = 0 {}
    |                  ^^^
@@ -589,7 +589,7 @@ LL |     while return let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:259:39
+  --> $DIR/disallowed-positions.rs:258:39
    |
 LL |     'outer: loop { while break 'outer let 0 = 0 {} }
    |                                       ^^^
@@ -597,7 +597,7 @@ LL |     'outer: loop { while break 'outer let 0 = 0 {} }
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:262:18
+  --> $DIR/disallowed-positions.rs:261:18
    |
 LL |     while (match let 0 = 0 { _ => { false } }) {}
    |                  ^^^
@@ -605,7 +605,7 @@ LL |     while (match let 0 = 0 { _ => { false } }) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:265:12
+  --> $DIR/disallowed-positions.rs:264:12
    |
 LL |     while (let 0 = 0, false).1 {}
    |            ^^^^^^^^^
@@ -613,7 +613,7 @@ LL |     while (let 0 = 0, false).1 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:268:12
+  --> $DIR/disallowed-positions.rs:267:12
    |
 LL |     while (let 0 = 0,) {}
    |            ^^^^^^^^^
@@ -621,7 +621,7 @@ LL |     while (let 0 = 0,) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:272:16
+  --> $DIR/disallowed-positions.rs:271:16
    |
 LL |         while (let 0 = 0).await {}
    |                ^^^^^^^^^
@@ -629,7 +629,7 @@ LL |         while (let 0 = 0).await {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:276:15
+  --> $DIR/disallowed-positions.rs:275:15
    |
 LL |     while (|| let 0 = 0) {}
    |               ^^^
@@ -637,7 +637,7 @@ LL |     while (|| let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:279:12
+  --> $DIR/disallowed-positions.rs:278:12
    |
 LL |     while (let 0 = 0)() {}
    |            ^^^^^^^^^
@@ -645,7 +645,7 @@ LL |     while (let 0 = 0)() {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:296:6
+  --> $DIR/disallowed-positions.rs:295:6
    |
 LL |     &let 0 = 0;
    |      ^^^
@@ -653,7 +653,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:299:6
+  --> $DIR/disallowed-positions.rs:298:6
    |
 LL |     !let 0 = 0;
    |      ^^^
@@ -661,7 +661,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:301:6
+  --> $DIR/disallowed-positions.rs:300:6
    |
 LL |     *let 0 = 0;
    |      ^^^
@@ -669,7 +669,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:303:6
+  --> $DIR/disallowed-positions.rs:302:6
    |
 LL |     -let 0 = 0;
    |      ^^^
@@ -677,7 +677,7 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:305:13
+  --> $DIR/disallowed-positions.rs:304:13
    |
 LL |     let _ = let _ = 3;
    |             ^^^
@@ -685,7 +685,7 @@ LL |     let _ = let _ = 3;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:313:6
+  --> $DIR/disallowed-positions.rs:312:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
@@ -693,7 +693,7 @@ LL |     (let 0 = 0)?;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:316:13
+  --> $DIR/disallowed-positions.rs:315:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
@@ -701,7 +701,7 @@ LL |     true || let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:318:14
+  --> $DIR/disallowed-positions.rs:317:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
@@ -709,7 +709,7 @@ LL |     (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:320:22
+  --> $DIR/disallowed-positions.rs:319:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
@@ -717,7 +717,7 @@ LL |     true && (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:324:9
+  --> $DIR/disallowed-positions.rs:323:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
@@ -725,7 +725,7 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:327:12
+  --> $DIR/disallowed-positions.rs:326:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
@@ -733,7 +733,7 @@ LL |     true..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:329:8
+  --> $DIR/disallowed-positions.rs:328:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
@@ -741,7 +741,7 @@ LL |     ..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:331:6
+  --> $DIR/disallowed-positions.rs:330:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
@@ -749,7 +749,7 @@ LL |     (let 0 = 0)..;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:334:6
+  --> $DIR/disallowed-positions.rs:333:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
@@ -757,7 +757,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:338:6
+  --> $DIR/disallowed-positions.rs:337:6
    |
 LL |     (let true = let true = true);
    |      ^^^
@@ -765,7 +765,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:338:17
+  --> $DIR/disallowed-positions.rs:337:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
@@ -773,7 +773,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:344:25
+  --> $DIR/disallowed-positions.rs:343:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
@@ -781,7 +781,7 @@ LL |         let x = true && let y = 1;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:350:19
+  --> $DIR/disallowed-positions.rs:349:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
@@ -789,7 +789,7 @@ LL |         [1, 2, 3][let _ = ()]
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:355:6
+  --> $DIR/disallowed-positions.rs:354:6
    |
 LL |     &let 0 = 0
    |      ^^^
@@ -797,7 +797,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:366:17
+  --> $DIR/disallowed-positions.rs:365:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -805,7 +805,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:371:17
+  --> $DIR/disallowed-positions.rs:370:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -813,7 +813,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:376:17
+  --> $DIR/disallowed-positions.rs:375:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -821,7 +821,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:387:17
+  --> $DIR/disallowed-positions.rs:386:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -829,7 +829,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:387:9
+  --> $DIR/disallowed-positions.rs:386:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -840,124 +840,124 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:397:9
+  --> $DIR/disallowed-positions.rs:396:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:397:9
+  --> $DIR/disallowed-positions.rs:396:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:401:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:401:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:404:9
+  --> $DIR/disallowed-positions.rs:403:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:404:9
+  --> $DIR/disallowed-positions.rs:403:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:404:32
+  --> $DIR/disallowed-positions.rs:403:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:404:32
+  --> $DIR/disallowed-positions.rs:403:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:412:9
+  --> $DIR/disallowed-positions.rs:411:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:412:9
+  --> $DIR/disallowed-positions.rs:411:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:412:31
+  --> $DIR/disallowed-positions.rs:411:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:412:31
+  --> $DIR/disallowed-positions.rs:411:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:416:9
+  --> $DIR/disallowed-positions.rs:415:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:416:9
+  --> $DIR/disallowed-positions.rs:415:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:416:31
+  --> $DIR/disallowed-positions.rs:415:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:416:31
+  --> $DIR/disallowed-positions.rs:415:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:420:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:420:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:440:22
+  --> $DIR/disallowed-positions.rs:439:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
@@ -965,7 +965,7 @@ LL |     let x = (true && let y = 1);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:445:20
+  --> $DIR/disallowed-positions.rs:444:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
@@ -973,7 +973,7 @@ LL |         ([1, 2, 3][let _ = ()])
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:91:16
+  --> $DIR/disallowed-positions.rs:90:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -981,7 +981,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:91:16
+  --> $DIR/disallowed-positions.rs:90:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -990,7 +990,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:91:16
+  --> $DIR/disallowed-positions.rs:90:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -999,7 +999,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:95:16
+  --> $DIR/disallowed-positions.rs:94:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -1007,7 +1007,7 @@ LL |     use_expr!((let 0 = 1));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:95:16
+  --> $DIR/disallowed-positions.rs:94:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -1016,7 +1016,7 @@ LL |     use_expr!((let 0 = 1));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:95:16
+  --> $DIR/disallowed-positions.rs:94:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -1025,7 +1025,7 @@ LL |     use_expr!((let 0 = 1));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:134:8
+  --> $DIR/disallowed-positions.rs:133:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -1034,7 +1034,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:143:12
+  --> $DIR/disallowed-positions.rs:142:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1045,7 +1045,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:146:12
+  --> $DIR/disallowed-positions.rs:145:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1056,7 +1056,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:152:12
+  --> $DIR/disallowed-positions.rs:151:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1067,7 +1067,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:158:12
+  --> $DIR/disallowed-positions.rs:157:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1078,7 +1078,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:114:20
+  --> $DIR/disallowed-positions.rs:113:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1086,7 +1086,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:225:11
+  --> $DIR/disallowed-positions.rs:224:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -1095,7 +1095,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:234:15
+  --> $DIR/disallowed-positions.rs:233:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1106,7 +1106,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:237:15
+  --> $DIR/disallowed-positions.rs:236:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1117,7 +1117,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:243:15
+  --> $DIR/disallowed-positions.rs:242:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1128,7 +1128,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:249:15
+  --> $DIR/disallowed-positions.rs:248:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1139,7 +1139,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:205:23
+  --> $DIR/disallowed-positions.rs:204:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1147,7 +1147,7 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:334:10
+  --> $DIR/disallowed-positions.rs:333:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1158,7 +1158,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:309:17
+  --> $DIR/disallowed-positions.rs:308:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
index 5b53691cbf5..f69c18ff0d9 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
@@ -1,239 +1,239 @@
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:36:11
+  --> $DIR/disallowed-positions.rs:35:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:36:11
+  --> $DIR/disallowed-positions.rs:35:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:39:9
+  --> $DIR/disallowed-positions.rs:38:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:39:9
+  --> $DIR/disallowed-positions.rs:38:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:42:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:42:17
+  --> $DIR/disallowed-positions.rs:41:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:9
+  --> $DIR/disallowed-positions.rs:44:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:9
+  --> $DIR/disallowed-positions.rs:44:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:24
+  --> $DIR/disallowed-positions.rs:44:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:24
+  --> $DIR/disallowed-positions.rs:44:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:48
+  --> $DIR/disallowed-positions.rs:48:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:49:61
+  --> $DIR/disallowed-positions.rs:48:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:49:35
+  --> $DIR/disallowed-positions.rs:48:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:58:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:59:12
+  --> $DIR/disallowed-positions.rs:58:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:62:14
+  --> $DIR/disallowed-positions.rs:61:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:62:14
+  --> $DIR/disallowed-positions.rs:61:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:68:20
+  --> $DIR/disallowed-positions.rs:67:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:68:20
+  --> $DIR/disallowed-positions.rs:67:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:71:12
+  --> $DIR/disallowed-positions.rs:70:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:71:12
+  --> $DIR/disallowed-positions.rs:70:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:71:27
+  --> $DIR/disallowed-positions.rs:70:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:71:27
+  --> $DIR/disallowed-positions.rs:70:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:51
+  --> $DIR/disallowed-positions.rs:74:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:75:64
+  --> $DIR/disallowed-positions.rs:74:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:75:38
+  --> $DIR/disallowed-positions.rs:74:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:103:9
+  --> $DIR/disallowed-positions.rs:102:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -241,7 +241,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:106:9
+  --> $DIR/disallowed-positions.rs:105:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -249,7 +249,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:108:9
+  --> $DIR/disallowed-positions.rs:107:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -257,7 +257,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:110:9
+  --> $DIR/disallowed-positions.rs:109:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -265,7 +265,7 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:118:9
+  --> $DIR/disallowed-positions.rs:117:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -273,13 +273,13 @@ LL |     if (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `||` operators are not supported in let chain conditions
-  --> $DIR/disallowed-positions.rs:121:13
+  --> $DIR/disallowed-positions.rs:120:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:123:17
+  --> $DIR/disallowed-positions.rs:122:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -287,7 +287,7 @@ LL |     if (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:125:25
+  --> $DIR/disallowed-positions.rs:124:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -295,7 +295,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:127:25
+  --> $DIR/disallowed-positions.rs:126:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -303,7 +303,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:131:12
+  --> $DIR/disallowed-positions.rs:130:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
@@ -311,7 +311,7 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:134:15
+  --> $DIR/disallowed-positions.rs:133:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -319,7 +319,7 @@ LL |     if true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:137:11
+  --> $DIR/disallowed-positions.rs:136:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -327,7 +327,7 @@ LL |     if ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:139:9
+  --> $DIR/disallowed-positions.rs:138:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -335,7 +335,7 @@ LL |     if (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:143:8
+  --> $DIR/disallowed-positions.rs:142:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -343,7 +343,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:146:8
+  --> $DIR/disallowed-positions.rs:145:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -351,7 +351,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:152:8
+  --> $DIR/disallowed-positions.rs:151:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -359,7 +359,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:158:8
+  --> $DIR/disallowed-positions.rs:157:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +367,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:162:19
+  --> $DIR/disallowed-positions.rs:161:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
@@ -375,7 +375,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:165:15
+  --> $DIR/disallowed-positions.rs:164:15
    |
 LL |     if return let 0 = 0 {}
    |               ^^^
@@ -383,7 +383,7 @@ LL |     if return let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:168:21
+  --> $DIR/disallowed-positions.rs:167:21
    |
 LL |     loop { if break let 0 = 0 {} }
    |                     ^^^
@@ -391,7 +391,7 @@ LL |     loop { if break let 0 = 0 {} }
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:171:15
+  --> $DIR/disallowed-positions.rs:170:15
    |
 LL |     if (match let 0 = 0 { _ => { false } }) {}
    |               ^^^
@@ -399,7 +399,7 @@ LL |     if (match let 0 = 0 { _ => { false } }) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:174:9
+  --> $DIR/disallowed-positions.rs:173:9
    |
 LL |     if (let 0 = 0, false).1 {}
    |         ^^^^^^^^^
@@ -407,7 +407,7 @@ LL |     if (let 0 = 0, false).1 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:177:9
+  --> $DIR/disallowed-positions.rs:176:9
    |
 LL |     if (let 0 = 0,) {}
    |         ^^^^^^^^^
@@ -415,7 +415,7 @@ LL |     if (let 0 = 0,) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:181:13
+  --> $DIR/disallowed-positions.rs:180:13
    |
 LL |         if (let 0 = 0).await {}
    |             ^^^^^^^^^
@@ -423,7 +423,7 @@ LL |         if (let 0 = 0).await {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:185:12
+  --> $DIR/disallowed-positions.rs:184:12
    |
 LL |     if (|| let 0 = 0) {}
    |            ^^^
@@ -431,7 +431,7 @@ LL |     if (|| let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:188:9
+  --> $DIR/disallowed-positions.rs:187:9
    |
 LL |     if (let 0 = 0)() {}
    |         ^^^^^^^^^
@@ -439,7 +439,7 @@ LL |     if (let 0 = 0)() {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:194:12
+  --> $DIR/disallowed-positions.rs:193:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -447,7 +447,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:197:12
+  --> $DIR/disallowed-positions.rs:196:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -455,7 +455,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:199:12
+  --> $DIR/disallowed-positions.rs:198:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -463,7 +463,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:201:12
+  --> $DIR/disallowed-positions.rs:200:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -471,7 +471,7 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:209:12
+  --> $DIR/disallowed-positions.rs:208:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -479,13 +479,13 @@ LL |     while (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `||` operators are not supported in let chain conditions
-  --> $DIR/disallowed-positions.rs:212:16
+  --> $DIR/disallowed-positions.rs:211:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:214:20
+  --> $DIR/disallowed-positions.rs:213:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -493,7 +493,7 @@ LL |     while (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:216:28
+  --> $DIR/disallowed-positions.rs:215:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -501,7 +501,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:218:28
+  --> $DIR/disallowed-positions.rs:217:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -509,7 +509,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:222:15
+  --> $DIR/disallowed-positions.rs:221:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
@@ -517,7 +517,7 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:225:18
+  --> $DIR/disallowed-positions.rs:224:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -525,7 +525,7 @@ LL |     while true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:228:14
+  --> $DIR/disallowed-positions.rs:227:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -533,7 +533,7 @@ LL |     while ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:230:12
+  --> $DIR/disallowed-positions.rs:229:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -541,7 +541,7 @@ LL |     while (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:234:11
+  --> $DIR/disallowed-positions.rs:233:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -549,7 +549,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:237:11
+  --> $DIR/disallowed-positions.rs:236:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -557,7 +557,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:243:11
+  --> $DIR/disallowed-positions.rs:242:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -565,7 +565,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:249:11
+  --> $DIR/disallowed-positions.rs:248:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -573,7 +573,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:253:22
+  --> $DIR/disallowed-positions.rs:252:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
@@ -581,7 +581,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:256:18
+  --> $DIR/disallowed-positions.rs:255:18
    |
 LL |     while return let 0 = 0 {}
    |                  ^^^
@@ -589,7 +589,7 @@ LL |     while return let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:259:39
+  --> $DIR/disallowed-positions.rs:258:39
    |
 LL |     'outer: loop { while break 'outer let 0 = 0 {} }
    |                                       ^^^
@@ -597,7 +597,7 @@ LL |     'outer: loop { while break 'outer let 0 = 0 {} }
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:262:18
+  --> $DIR/disallowed-positions.rs:261:18
    |
 LL |     while (match let 0 = 0 { _ => { false } }) {}
    |                  ^^^
@@ -605,7 +605,7 @@ LL |     while (match let 0 = 0 { _ => { false } }) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:265:12
+  --> $DIR/disallowed-positions.rs:264:12
    |
 LL |     while (let 0 = 0, false).1 {}
    |            ^^^^^^^^^
@@ -613,7 +613,7 @@ LL |     while (let 0 = 0, false).1 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:268:12
+  --> $DIR/disallowed-positions.rs:267:12
    |
 LL |     while (let 0 = 0,) {}
    |            ^^^^^^^^^
@@ -621,7 +621,7 @@ LL |     while (let 0 = 0,) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:272:16
+  --> $DIR/disallowed-positions.rs:271:16
    |
 LL |         while (let 0 = 0).await {}
    |                ^^^^^^^^^
@@ -629,7 +629,7 @@ LL |         while (let 0 = 0).await {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:276:15
+  --> $DIR/disallowed-positions.rs:275:15
    |
 LL |     while (|| let 0 = 0) {}
    |               ^^^
@@ -637,7 +637,7 @@ LL |     while (|| let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:279:12
+  --> $DIR/disallowed-positions.rs:278:12
    |
 LL |     while (let 0 = 0)() {}
    |            ^^^^^^^^^
@@ -645,7 +645,7 @@ LL |     while (let 0 = 0)() {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:296:6
+  --> $DIR/disallowed-positions.rs:295:6
    |
 LL |     &let 0 = 0;
    |      ^^^
@@ -653,7 +653,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:299:6
+  --> $DIR/disallowed-positions.rs:298:6
    |
 LL |     !let 0 = 0;
    |      ^^^
@@ -661,7 +661,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:301:6
+  --> $DIR/disallowed-positions.rs:300:6
    |
 LL |     *let 0 = 0;
    |      ^^^
@@ -669,7 +669,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:303:6
+  --> $DIR/disallowed-positions.rs:302:6
    |
 LL |     -let 0 = 0;
    |      ^^^
@@ -677,7 +677,7 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:305:13
+  --> $DIR/disallowed-positions.rs:304:13
    |
 LL |     let _ = let _ = 3;
    |             ^^^
@@ -685,7 +685,7 @@ LL |     let _ = let _ = 3;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:313:6
+  --> $DIR/disallowed-positions.rs:312:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
@@ -693,7 +693,7 @@ LL |     (let 0 = 0)?;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:316:13
+  --> $DIR/disallowed-positions.rs:315:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
@@ -701,7 +701,7 @@ LL |     true || let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:318:14
+  --> $DIR/disallowed-positions.rs:317:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
@@ -709,7 +709,7 @@ LL |     (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:320:22
+  --> $DIR/disallowed-positions.rs:319:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
@@ -717,7 +717,7 @@ LL |     true && (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:324:9
+  --> $DIR/disallowed-positions.rs:323:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
@@ -725,7 +725,7 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:327:12
+  --> $DIR/disallowed-positions.rs:326:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
@@ -733,7 +733,7 @@ LL |     true..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:329:8
+  --> $DIR/disallowed-positions.rs:328:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
@@ -741,7 +741,7 @@ LL |     ..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:331:6
+  --> $DIR/disallowed-positions.rs:330:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
@@ -749,7 +749,7 @@ LL |     (let 0 = 0)..;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:334:6
+  --> $DIR/disallowed-positions.rs:333:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
@@ -757,7 +757,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:338:6
+  --> $DIR/disallowed-positions.rs:337:6
    |
 LL |     (let true = let true = true);
    |      ^^^
@@ -765,7 +765,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:338:17
+  --> $DIR/disallowed-positions.rs:337:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
@@ -773,7 +773,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:344:25
+  --> $DIR/disallowed-positions.rs:343:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
@@ -781,7 +781,7 @@ LL |         let x = true && let y = 1;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:350:19
+  --> $DIR/disallowed-positions.rs:349:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
@@ -789,7 +789,7 @@ LL |         [1, 2, 3][let _ = ()]
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:355:6
+  --> $DIR/disallowed-positions.rs:354:6
    |
 LL |     &let 0 = 0
    |      ^^^
@@ -797,7 +797,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:366:17
+  --> $DIR/disallowed-positions.rs:365:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -805,7 +805,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:371:17
+  --> $DIR/disallowed-positions.rs:370:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -813,7 +813,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:376:17
+  --> $DIR/disallowed-positions.rs:375:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -821,7 +821,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:387:17
+  --> $DIR/disallowed-positions.rs:386:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -829,7 +829,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:387:9
+  --> $DIR/disallowed-positions.rs:386:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -840,124 +840,124 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:397:9
+  --> $DIR/disallowed-positions.rs:396:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:397:9
+  --> $DIR/disallowed-positions.rs:396:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:401:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:401:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:404:9
+  --> $DIR/disallowed-positions.rs:403:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:404:9
+  --> $DIR/disallowed-positions.rs:403:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:404:32
+  --> $DIR/disallowed-positions.rs:403:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:404:32
+  --> $DIR/disallowed-positions.rs:403:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:412:9
+  --> $DIR/disallowed-positions.rs:411:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:412:9
+  --> $DIR/disallowed-positions.rs:411:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:412:31
+  --> $DIR/disallowed-positions.rs:411:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:412:31
+  --> $DIR/disallowed-positions.rs:411:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:416:9
+  --> $DIR/disallowed-positions.rs:415:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:416:9
+  --> $DIR/disallowed-positions.rs:415:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:416:31
+  --> $DIR/disallowed-positions.rs:415:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:416:31
+  --> $DIR/disallowed-positions.rs:415:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:420:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:420:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:440:22
+  --> $DIR/disallowed-positions.rs:439:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
@@ -965,7 +965,7 @@ LL |     let x = (true && let y = 1);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:445:20
+  --> $DIR/disallowed-positions.rs:444:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
index 65beccf2214..142ea6b4ea8 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -1,5 +1,7 @@
-//@ revisions: no_feature feature nothing
-//@ edition: 2021
+//@ revisions: e2021 e2024 nothing
+//@ [e2021] edition: 2021
+//@ [e2024] edition: 2024
+//@ [nothing] edition: 2024
 // Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions.
 //
 // We want to make sure that `let` is banned in situations other than:
@@ -19,9 +21,6 @@
 //
 // To that end, we check some positions which is not part of the language above.
 
-// Avoid inflating `.stderr` with overzealous gates (or test what happens if you disable the gate)
-#![cfg_attr(not(no_feature), feature(let_chains))]
-
 #![allow(irrefutable_let_patterns)]
 
 use std::ops::Range;
@@ -50,8 +49,8 @@ fn _if() {
     //~^ ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
-    //[no_feature]~| ERROR `let` expressions in this position are unstable
-    //[no_feature]~| ERROR `let` expressions in this position are unstable
+    //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later
+    //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later
 }
 
 #[cfg(not(nothing))]
@@ -76,8 +75,8 @@ fn _while() {
     //~^ ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
-    //[no_feature]~| ERROR `let` expressions in this position are unstable
-    //[no_feature]~| ERROR `let` expressions in this position are unstable
+    //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later
+    //[e2021]~| ERROR let chains are only allowed in Rust 2024 or later
 }
 
 #[cfg(not(nothing))]
@@ -89,13 +88,13 @@ fn _macros() {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //[feature,no_feature]~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR expected expression, found `let` statement
+    //[e2021,e2024]~^ ERROR expected expression, found `let` statement
+    //[e2021,e2024]~| ERROR expected expression, found `let` statement
+    //[e2021,e2024]~| ERROR expected expression, found `let` statement
     use_expr!((let 0 = 1));
-    //[feature,no_feature]~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR expected expression, found `let` statement
+    //[e2021,e2024]~^ ERROR expected expression, found `let` statement
+    //[e2021,e2024]~| ERROR expected expression, found `let` statement
+    //[e2021,e2024]~| ERROR expected expression, found `let` statement
 }
 
 #[cfg(not(nothing))]
@@ -112,7 +111,7 @@ fn nested_within_if_expr() {
 
     fn _check_try_binds_tighter() -> Result<(), ()> {
         if let 0 = 0? {}
-        //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try`
+        //[e2021,e2024]~^ ERROR the `?` operator can only be applied to values that implement `Try`
         Ok(())
     }
     if (let 0 = 0)? {}
@@ -133,7 +132,7 @@ fn nested_within_if_expr() {
 
     if true..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
     if ..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
     if (let 0 = 0).. {}
@@ -142,22 +141,22 @@ fn nested_within_if_expr() {
     // Binds as `(let ... = true)..true &&/|| false`.
     if let Range { start: _, end: _ } = true..true && false {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
     if let Range { start: _, end: _ } = true..true || false {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
 
     // Binds as `(let Range { start: F, end } = F)..(|| true)`.
     const F: fn() -> bool = || true;
     if let Range { start: F, end } = F..|| true {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
 
     // Binds as `(let Range { start: true, end } = t)..(&&false)`.
     let t = &&true;
     if let Range { start: true, end } = t..&&false {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
 
     if let true = let true = true {}
     //~^ ERROR expected expression, found `let` statement
@@ -203,7 +202,7 @@ fn nested_within_while_expr() {
 
     fn _check_try_binds_tighter() -> Result<(), ()> {
         while let 0 = 0? {}
-        //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try`
+        //[e2021,e2024]~^ ERROR the `?` operator can only be applied to values that implement `Try`
         Ok(())
     }
     while (let 0 = 0)? {}
@@ -224,7 +223,7 @@ fn nested_within_while_expr() {
 
     while true..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
     while ..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
     while (let 0 = 0).. {}
@@ -233,22 +232,22 @@ fn nested_within_while_expr() {
     // Binds as `(let ... = true)..true &&/|| false`.
     while let Range { start: _, end: _ } = true..true && false {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
     while let Range { start: _, end: _ } = true..true || false {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
 
     // Binds as `(let Range { start: F, end } = F)..(|| true)`.
     const F: fn() -> bool = || true;
     while let Range { start: F, end } = F..|| true {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
 
     // Binds as `(let Range { start: true, end } = t)..(&&false)`.
     let t = &&true;
     while let Range { start: true, end } = t..&&false {}
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
 
     while let true = let true = true {}
     //~^ ERROR expected expression, found `let` statement
@@ -307,7 +306,7 @@ fn outside_if_and_while_expr() {
 
     fn _check_try_binds_tighter() -> Result<(), ()> {
         let 0 = 0?;
-        //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try`
+        //[e2021,e2024]~^ ERROR the `?` operator can only be applied to values that implement `Try`
         Ok(())
     }
     (let 0 = 0)?;
@@ -333,7 +332,7 @@ fn outside_if_and_while_expr() {
 
     (let Range { start: _, end: _ } = true..true || false);
     //~^ ERROR expected expression, found `let` statement
-    //[feature,no_feature]~| ERROR mismatched types
+    //[e2021,e2024]~| ERROR mismatched types
 
     (let true = let true = true);
     //~^ ERROR expected expression, found `let` statement
@@ -406,7 +405,7 @@ fn with_parenthesis() {
     //~| ERROR expected expression, found `let` statement
     }
     if let Some(a) = opt && (true && true) {
-    //[no_feature]~^ ERROR `let` expressions in this position are unstable
+    //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later
     }
 
     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
@@ -422,18 +421,18 @@ fn with_parenthesis() {
     }
 
     if (true && (true)) && let Some(a) = opt {
-    //[no_feature]~^ ERROR `let` expressions in this position are unstable
+    //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later
     }
     if (true) && let Some(a) = opt {
-    //[no_feature]~^ ERROR `let` expressions in this position are unstable
+    //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later
     }
     if true && let Some(a) = opt {
-    //[no_feature]~^ ERROR `let` expressions in this position are unstable
+    //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later
     }
 
     let fun = || true;
     if let true = (true && fun()) && (true) {
-    //[no_feature]~^ ERROR `let` expressions in this position are unstable
+    //[e2021]~^ ERROR let chains are only allowed in Rust 2024 or later
     }
 
     #[cfg(false)]
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr
index 23700f89f10..7fc91e9d980 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr
@@ -1,65 +1,42 @@
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:19:30
    |
 LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
    |                              ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:19:52
    |
 LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
    |                                                    ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:22:5
    |
 LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:22:5
    |
 LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:26:30
    |
 LL |     macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
    |                              ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:26:52
    |
 LL |     macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
    |                                                    ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr
index 3af844f4f96..35ac848561c 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr
@@ -1,45 +1,30 @@
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:19:30
    |
 LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
    |                              ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:19:52
    |
 LL |     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
    |                                                    ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:22:5
    |
 LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0658]: `let` expressions in this position are unstable
+error: let chains are only allowed in Rust 2024 or later
   --> $DIR/edition-gate-macro-error.rs:22:5
    |
 LL |     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs
index 89b555d2c50..a56c11264c1 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs
@@ -17,14 +17,14 @@ fn main() {
     // No gating if both the `if` and the chain are from a 2024 macro
 
     macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
-    //~^ ERROR `let` expressions in this position are unstable
-    //~| ERROR `let` expressions in this position are unstable
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
+    //~| ERROR let chains are only allowed in Rust 2024 or later
     macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
-    //~^ ERROR `let` expressions in this position are unstable
-    //~| ERROR `let` expressions in this position are unstable
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
+    //~| ERROR let chains are only allowed in Rust 2024 or later
 
     macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
-    //[edition2021]~^ ERROR `let` expressions in this position are unstable
-    //[edition2021]~| ERROR `let` expressions in this position are unstable
+    //[edition2021]~^ ERROR let chains are only allowed in Rust 2024 or later
+    //[edition2021]~| ERROR let chains are only allowed in Rust 2024 or later
     macro_in_2024::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
 }
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.rs
index dad02b7f106..0096e6985d3 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.rs
@@ -1,6 +1,4 @@
-// gate-test-let_chains
-
-// Here we test feature gating for ´let_chains`.
+// Here we test Rust 2024 edition gating for ´let_chains`.
 // See `disallowed-positions.rs` for the grammar
 // defining the language for gated allowed positions.
 
@@ -12,17 +10,17 @@ fn _if() {
     if let 0 = 1 {} // Stable!
 
     if true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
 
     if let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
 
     if let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
 
     if let 1 = 1 && let true = { true } && false {
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
+    //~| ERROR let chains are only allowed in Rust 2024 or later
     }
 }
 
@@ -30,13 +28,13 @@ fn _while() {
     while let 0 = 1 {} // Stable!
 
     while true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
 
     while let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
 
     while let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~^ ERROR let chains are only allowed in Rust 2024 or later
 }
 
 fn _macros() {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.stderr
new file mode 100644
index 00000000000..f75dd858941
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate.stderr
@@ -0,0 +1,81 @@
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:12:16
+   |
+LL |     if true && let 0 = 1 {}
+   |                ^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:15:8
+   |
+LL |     if let 0 = 1 && true {}
+   |        ^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:18:8
+   |
+LL |     if let Range { start: _, end: _ } = (true..true) && false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:21:8
+   |
+LL |     if let 1 = 1 && let true = { true } && false {
+   |        ^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:21:21
+   |
+LL |     if let 1 = 1 && let true = { true } && false {
+   |                     ^^^^^^^^^^^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:30:19
+   |
+LL |     while true && let 0 = 1 {}
+   |                   ^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:33:11
+   |
+LL |     while let 0 = 1 && true {}
+   |           ^^^^^^^^^
+
+error: let chains are only allowed in Rust 2024 or later
+  --> $DIR/edition-gate.rs:36:11
+   |
+LL |     while let Range { start: _, end: _ } = (true..true) && false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/edition-gate.rs:52:20
+   |
+LL |     #[cfg(false)] (let 0 = 1);
+   |                    ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/edition-gate.rs:43:17
+   |
+LL |     noop_expr!((let 0 = 1));
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: no rules expected keyword `let`
+  --> $DIR/edition-gate.rs:54:15
+   |
+LL |     macro_rules! use_expr {
+   |     --------------------- when calling this macro
+...
+LL |     use_expr!(let 0 = 1);
+   |               ^^^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:expr`
+  --> $DIR/edition-gate.rs:47:10
+   |
+LL |         ($e:expr) => {
+   |          ^^^^^^^
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
deleted file mode 100644
index b9dac472dca..00000000000
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
+++ /dev/null
@@ -1,114 +0,0 @@
-error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:54:20
-   |
-LL |     #[cfg(false)] (let 0 = 1);
-   |                    ^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-
-error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:45:17
-   |
-LL |     noop_expr!((let 0 = 1));
-   |                 ^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-
-error: no rules expected keyword `let`
-  --> $DIR/feature-gate.rs:56:15
-   |
-LL |     macro_rules! use_expr {
-   |     --------------------- when calling this macro
-...
-LL |     use_expr!(let 0 = 1);
-   |               ^^^ no rules expected this token in macro call
-   |
-note: while trying to match meta-variable `$e:expr`
-  --> $DIR/feature-gate.rs:49:10
-   |
-LL |         ($e:expr) => {
-   |          ^^^^^^^
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:14:16
-   |
-LL |     if true && let 0 = 1 {}
-   |                ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:17:8
-   |
-LL |     if let 0 = 1 && true {}
-   |        ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:20:8
-   |
-LL |     if let Range { start: _, end: _ } = (true..true) && false {}
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:23:8
-   |
-LL |     if let 1 = 1 && let true = { true } && false {
-   |        ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:23:21
-   |
-LL |     if let 1 = 1 && let true = { true } && false {
-   |                     ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:19
-   |
-LL |     while true && let 0 = 1 {}
-   |                   ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:35:11
-   |
-LL |     while let 0 = 1 && true {}
-   |           ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:38:11
-   |
-LL |     while let Range { start: _, end: _ } = (true..true) && false {}
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 11 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
index ae525aed414..3711dd5abb2 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
 
 fn main() {
     let _opt = Some(1i32);
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
index 130d0296c5e..008e769cf0b 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
@@ -1,19 +1,19 @@
 error: leading irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:13:8
+  --> $DIR/irrefutable-lets.rs:14:8
    |
-LL |     if let first = &opt && let Some(ref second) = first && let None = second.start {}
+LL |     if let first = &opt && let Some(second) = first && let None = second.start {}
    |        ^^^^^^^^^^^^^^^^
    |
    = note: this pattern will always match
    = help: consider moving it outside of the construct
 note: the lint level is defined here
-  --> $DIR/irrefutable-lets.rs:6:30
+  --> $DIR/irrefutable-lets.rs:7:30
    |
 LL | #![cfg_attr(disallowed, deny(irrefutable_let_patterns))]
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: irrefutable `if let` patterns
-  --> $DIR/irrefutable-lets.rs:19:8
+  --> $DIR/irrefutable-lets.rs:20:8
    |
 LL |     if let first = &opt && let (a, b) = (1, 2) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,25 +22,25 @@ LL |     if let first = &opt && let (a, b) = (1, 2) {}
    = help: consider replacing the `if let` with a `let`
 
 error: leading irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:22:8
+  --> $DIR/irrefutable-lets.rs:23:8
    |
-LL |     if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {}
+LL |     if let first = &opt && let Some(second) = first && let None = second.start && let v = 0 {}
    |        ^^^^^^^^^^^^^^^^
    |
    = note: this pattern will always match
    = help: consider moving it outside of the construct
 
 error: trailing irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:22:87
+  --> $DIR/irrefutable-lets.rs:23:83
    |
-LL |     if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {}
-   |                                                                                       ^^^^^^^^^
+LL |     if let first = &opt && let Some(second) = first && let None = second.start && let v = 0 {}
+   |                                                                                   ^^^^^^^^^
    |
    = note: this pattern will always match
    = help: consider moving it into the body
 
 error: trailing irrefutable patterns in let chain
-  --> $DIR/irrefutable-lets.rs:26:37
+  --> $DIR/irrefutable-lets.rs:27:37
    |
 LL |     if let Some(ref first) = opt && let second = first && let _third = second {}
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |     if let Some(ref first) = opt && let second = first && let _third = seco
    = help: consider moving them into the body
 
 error: leading irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:29:8
+  --> $DIR/irrefutable-lets.rs:30:8
    |
 LL |     if let Range { start: local_start, end: _ } = (None..Some(1)) && let None = local_start {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -58,7 +58,7 @@ LL |     if let Range { start: local_start, end: _ } = (None..Some(1)) && let No
    = help: consider moving it outside of the construct
 
 error: leading irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:32:8
+  --> $DIR/irrefutable-lets.rs:33:8
    |
 LL |     if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -67,7 +67,7 @@ LL |     if let (a, b, c) = (Some(1), Some(1), Some(1)) && let None = Some(1) {}
    = help: consider moving it outside of the construct
 
 error: leading irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:35:8
+  --> $DIR/irrefutable-lets.rs:36:8
    |
 LL |     if let first = &opt && let None = Some(1) {}
    |        ^^^^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     if let first = &opt && let None = Some(1) {}
    = help: consider moving it outside of the construct
 
 error: irrefutable `if let` guard patterns
-  --> $DIR/irrefutable-lets.rs:44:28
+  --> $DIR/irrefutable-lets.rs:45:28
    |
 LL |         Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {},
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |         Some(ref first) if let second = first && let _third = second && let
    = help: consider removing the guard and adding a `let` inside the match arm
 
 error: trailing irrefutable patterns in let chain
-  --> $DIR/irrefutable-lets.rs:59:16
+  --> $DIR/irrefutable-lets.rs:60:16
    |
 LL |             && let v = local_end && let w = v => {},
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +94,7 @@ LL |             && let v = local_end && let w = v => {},
    = help: consider moving them into the body
 
 error: irrefutable `while let` patterns
-  --> $DIR/irrefutable-lets.rs:68:11
+  --> $DIR/irrefutable-lets.rs:69:11
    |
 LL |     while let first = &opt && let (a, b) = (1, 2) {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL |     while let first = &opt && let (a, b) = (1, 2) {}
    = help: consider instead using a `loop { ... }` with a `let` inside it
 
 error: trailing irrefutable patterns in let chain
-  --> $DIR/irrefutable-lets.rs:71:40
+  --> $DIR/irrefutable-lets.rs:72:40
    |
 LL |     while let Some(ref first) = opt && let second = first && let _third = second {}
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +112,7 @@ LL |     while let Some(ref first) = opt && let second = first && let _third = s
    = help: consider moving them into the body
 
 error: trailing irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:87:12
+  --> $DIR/irrefutable-lets.rs:88:12
    |
 LL |         && let x = &opt
    |            ^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL |         && let x = &opt
    = help: consider moving it into the body
 
 error: leading irrefutable pattern in let chain
-  --> $DIR/irrefutable-lets.rs:93:12
+  --> $DIR/irrefutable-lets.rs:94:12
    |
 LL |         if let x = opt.clone().map(|_| 1)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
index e7d69f89773..c8b9ac313ba 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
@@ -1,7 +1,8 @@
 //@ revisions: allowed disallowed
 //@[allowed] check-pass
+//@ edition: 2024
 
-#![feature(if_let_guard, let_chains)]
+#![feature(if_let_guard)]
 #![cfg_attr(allowed, allow(irrefutable_let_patterns))]
 #![cfg_attr(disallowed, deny(irrefutable_let_patterns))]
 
@@ -10,16 +11,16 @@ use std::ops::Range;
 fn main() {
     let opt = Some(None..Some(1));
 
-    if let first = &opt && let Some(ref second) = first && let None = second.start {}
+    if let first = &opt && let Some(second) = first && let None = second.start {}
     //[disallowed]~^ ERROR leading irrefutable pattern in let chain
 
     // No lint as the irrefutable pattern is surrounded by other stuff
-    if 4 * 2 == 0 && let first = &opt && let Some(ref second) = first && let None = second.start {}
+    if 4 * 2 == 0 && let first = &opt && let Some(second) = first && let None = second.start {}
 
     if let first = &opt && let (a, b) = (1, 2) {}
     //[disallowed]~^ ERROR irrefutable `if let` patterns
 
-    if let first = &opt && let Some(ref second) = first && let None = second.start && let v = 0 {}
+    if let first = &opt && let Some(second) = first && let None = second.start && let v = 0 {}
     //[disallowed]~^ ERROR leading irrefutable pattern in let chain
     //[disallowed]~^^ ERROR trailing irrefutable pattern in let chain
 
@@ -63,7 +64,7 @@ fn main() {
 
     // No error, despite the prefix being irrefutable: moving out could change the behaviour,
     // due to possible side effects of the operation.
-    while let first = &opt && let Some(ref second) = first && let None = second.start {}
+    while let first = &opt && let Some(second) = first && let None = second.start {}
 
     while let first = &opt && let (a, b) = (1, 2) {}
     //[disallowed]~^ ERROR irrefutable `while let` patterns
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs
index 6d307be90c1..287c73b41e9 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/then-else-blocks.rs
@@ -1,6 +1,7 @@
 //@ run-pass
+//@ edition: 2024
 
-#![feature(if_let_guard, let_chains)]
+#![feature(if_let_guard)]
 
 fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
     if let Some(first) = opt
diff --git a/tests/ui/sanitizer/cfi/closures.rs b/tests/ui/sanitizer/cfi/closures.rs
index 9f9002da674..424e70560db 100644
--- a/tests/ui/sanitizer/cfi/closures.rs
+++ b/tests/ui/sanitizer/cfi/closures.rs
@@ -31,7 +31,7 @@ fn dyn_fn_with_params() {
 
 #[test]
 fn call_fn_trait() {
-   let f: &(dyn Fn()) = &(|| {}) as _;
+   let f: &dyn Fn() = &(|| {}) as _;
    f.call(());
 }
 
@@ -47,7 +47,7 @@ fn use_fnmut<F: FnMut()>(mut f: F) {
 
 #[test]
 fn fn_to_fnmut() {
-    let f: &(dyn Fn()) = &(|| {}) as _;
+    let f: &dyn Fn() = &(|| {}) as _;
     use_fnmut(f);
 }
 
diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs
index 9ef7a686d25..d13098c3a6a 100644
--- a/tests/ui/target-feature/invalid-attribute.rs
+++ b/tests/ui/target-feature/invalid-attribute.rs
@@ -19,13 +19,16 @@ extern "Rust" {}
 
 #[target_feature = "+sse2"]
 //~^ ERROR malformed `target_feature` attribute
+//~| NOTE expected this to be a list
 #[target_feature(enable = "foo")]
 //~^ ERROR not valid for this target
 //~| NOTE `foo` is not valid for this target
 #[target_feature(bar)]
 //~^ ERROR malformed `target_feature` attribute
+//~| NOTE expected this to be of the form `enable = "..."`
 #[target_feature(disable = "baz")]
 //~^ ERROR malformed `target_feature` attribute
+//~| NOTE expected this to be of the form `enable = "..."`
 unsafe fn foo() {}
 
 #[target_feature(enable = "sse2")]
@@ -117,3 +120,8 @@ fn main() {
     || {};
     //~^ NOTE not a function
 }
+
+#[target_feature(enable = "+sse2")]
+//~^ ERROR `+sse2` is not valid for this target
+//~| NOTE `+sse2` is not valid for this target
+unsafe fn hey() {}
diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr
index 05ae49d6b0d..113c0c3695a 100644
--- a/tests/ui/target-feature/invalid-attribute.stderr
+++ b/tests/ui/target-feature/invalid-attribute.stderr
@@ -1,8 +1,29 @@
-error: malformed `target_feature` attribute input
+error[E0539]: malformed `target_feature` attribute input
   --> $DIR/invalid-attribute.rs:20:1
    |
 LL | #[target_feature = "+sse2"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]`
+
+error[E0539]: malformed `target_feature` attribute input
+  --> $DIR/invalid-attribute.rs:26:1
+   |
+LL | #[target_feature(bar)]
+   | ^^^^^^^^^^^^^^^^^---^^
+   | |                |
+   | |                expected this to be of the form `enable = "..."`
+   | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]`
+
+error[E0539]: malformed `target_feature` attribute input
+  --> $DIR/invalid-attribute.rs:29:1
+   |
+LL | #[target_feature(disable = "baz")]
+   | ^^^^^^^^^^^^^^^^^-------^^^^^^^^^^
+   | |                |
+   | |                expected this to be of the form `enable = "..."`
+   | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]`
 
 error: attribute should be applied to a function definition
   --> $DIR/invalid-attribute.rs:5:1
@@ -32,7 +53,7 @@ LL | extern "Rust" {}
    | ---------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:31:1
+  --> $DIR/invalid-attribute.rs:34:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +62,7 @@ LL | mod another {}
    | -------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:36:1
+  --> $DIR/invalid-attribute.rs:39:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +71,7 @@ LL | const FOO: usize = 7;
    | --------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:41:1
+  --> $DIR/invalid-attribute.rs:44:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +80,7 @@ LL | struct Foo;
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:46:1
+  --> $DIR/invalid-attribute.rs:49:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +89,7 @@ LL | enum Bar {}
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:51:1
+  --> $DIR/invalid-attribute.rs:54:1
    |
 LL |   #[target_feature(enable = "sse2")]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,7 +102,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:59:1
+  --> $DIR/invalid-attribute.rs:62:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +111,7 @@ LL | type Uwu = ();
    | -------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:64:1
+  --> $DIR/invalid-attribute.rs:67:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -99,13 +120,13 @@ LL | trait Baz {}
    | ------------ not a function definition
 
 error: cannot use `#[inline(always)]` with `#[target_feature]`
-  --> $DIR/invalid-attribute.rs:69:1
+  --> $DIR/invalid-attribute.rs:72:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:74:1
+  --> $DIR/invalid-attribute.rs:77:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -114,7 +135,7 @@ LL | static A: () = ();
    | ------------------ not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:79:1
+  --> $DIR/invalid-attribute.rs:82:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -123,7 +144,7 @@ LL | impl Quux for u8 {}
    | ------------------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:86:1
+  --> $DIR/invalid-attribute.rs:89:1
    |
 LL | #[target_feature(enable = "sse2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +153,7 @@ LL | impl Foo {}
    | ----------- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:108:5
+  --> $DIR/invalid-attribute.rs:111:5
    |
 LL |       #[target_feature(enable = "sse2")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -143,7 +164,7 @@ LL | |     }
    | |_____- not a function definition
 
 error: attribute should be applied to a function definition
-  --> $DIR/invalid-attribute.rs:115:5
+  --> $DIR/invalid-attribute.rs:118:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -152,25 +173,13 @@ LL |     || {};
    |     ----- not a function definition
 
 error: the feature named `foo` is not valid for this target
-  --> $DIR/invalid-attribute.rs:22:18
+  --> $DIR/invalid-attribute.rs:23:18
    |
 LL | #[target_feature(enable = "foo")]
    |                  ^^^^^^^^^^^^^^ `foo` is not valid for this target
 
-error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:25:18
-   |
-LL | #[target_feature(bar)]
-   |                  ^^^ help: must be of the form: `enable = ".."`
-
-error: malformed `target_feature` attribute input
-  --> $DIR/invalid-attribute.rs:27:18
-   |
-LL | #[target_feature(disable = "baz")]
-   |                  ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
-
 error[E0046]: not all trait items implemented, missing: `foo`
-  --> $DIR/invalid-attribute.rs:81:1
+  --> $DIR/invalid-attribute.rs:84:1
    |
 LL | impl Quux for u8 {}
    | ^^^^^^^^^^^^^^^^ missing `foo` in implementation
@@ -179,7 +188,7 @@ LL |     fn foo();
    |     --------- `foo` from trait
 
 error: `#[target_feature(..)]` cannot be applied to safe trait method
-  --> $DIR/invalid-attribute.rs:97:5
+  --> $DIR/invalid-attribute.rs:100:5
    |
 LL |     #[target_feature(enable = "sse2")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
@@ -188,20 +197,28 @@ LL |     fn foo() {}
    |     -------- not an `unsafe` function
 
 error[E0053]: method `foo` has an incompatible type for trait
-  --> $DIR/invalid-attribute.rs:100:5
+  --> $DIR/invalid-attribute.rs:103:5
    |
 LL |     fn foo() {}
    |     ^^^^^^^^ expected safe fn, found unsafe fn
    |
 note: type in trait
-  --> $DIR/invalid-attribute.rs:92:5
+  --> $DIR/invalid-attribute.rs:95:5
    |
 LL |     fn foo();
    |     ^^^^^^^^^
    = note: expected signature `fn()`
               found signature `#[target_features] fn()`
 
-error: aborting due to 23 previous errors
+error: the feature named `+sse2` is not valid for this target
+  --> $DIR/invalid-attribute.rs:124:18
+   |
+LL | #[target_feature(enable = "+sse2")]
+   |                  ^^^^^^^^^^^^^^^^ `+sse2` is not valid for this target
+   |
+   = help: consider removing the leading `+` in the feature name
+
+error: aborting due to 24 previous errors
 
-Some errors have detailed explanations: E0046, E0053.
+Some errors have detailed explanations: E0046, E0053, E0539.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout
index 828b93da6be..5c4c50cb156 100644
--- a/tests/ui/thir-print/thir-tree-loop-match.stdout
+++ b/tests/ui/thir-print/thir-tree-loop-match.stdout
@@ -89,158 +89,182 @@ body:
                                                                                             }
                                                                                     }
                                                                                 region_scope: Node(10)
-                                                                                match_span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0)
-                                                                                arms: [
-                                                                                    Arm {
-                                                                                        pattern: 
-                                                                                            Pat: {
-                                                                                                ty: bool
-                                                                                                span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0)
-                                                                                                kind: PatKind {
-                                                                                                    Constant {
-                                                                                                        value: Ty(bool, true)
-                                                                                                    }
-                                                                                                }
-                                                                                            }
-                                                                                        guard: None
-                                                                                        body: 
+                                                                                match_data:
+                                                                                    LoopMatchMatchData {
+                                                                                        span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0)
+                                                                                        scrutinee:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
-                                                                                                span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None }
+                                                                                                span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0)
                                                                                                 kind: 
                                                                                                     Scope {
-                                                                                                        region_scope: Node(17)
-                                                                                                        lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17))
+                                                                                                        region_scope: Node(12)
+                                                                                                        lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).12))
                                                                                                         value:
                                                                                                             Expr {
                                                                                                                 ty: bool
-                                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
-                                                                                                                span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
+                                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None }
+                                                                                                                span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0)
                                                                                                                 kind: 
-                                                                                                                    NeverToAny {
-                                                                                                                        source:
-                                                                                                                            Expr {
-                                                                                                                                ty: !
-                                                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
-                                                                                                                                span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
-                                                                                                                                kind: 
-                                                                                                                                    Block {
-                                                                                                                                        targeted_by_break: false
+                                                                                                                    VarRef {
+                                                                                                                        id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2))
+                                                                                                                    }
+                                                                                                            }
+                                                                                                    }
+                                                                                            }
+                                                                                        arms: [
+                                                                                            Arm {
+                                                                                                pattern: 
+                                                                                                    Pat: {
+                                                                                                        ty: bool
+                                                                                                        span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0)
+                                                                                                        kind: PatKind {
+                                                                                                            Constant {
+                                                                                                                value: Ty(bool, true)
+                                                                                                            }
+                                                                                                        }
+                                                                                                    }
+                                                                                                guard: None
+                                                                                                body: 
+                                                                                                    Expr {
+                                                                                                        ty: bool
+                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
+                                                                                                        span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
+                                                                                                        kind: 
+                                                                                                            Scope {
+                                                                                                                region_scope: Node(17)
+                                                                                                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).17))
+                                                                                                                value:
+                                                                                                                    Expr {
+                                                                                                                        ty: bool
+                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
+                                                                                                                        span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
+                                                                                                                        kind: 
+                                                                                                                            NeverToAny {
+                                                                                                                                source:
+                                                                                                                                    Expr {
+                                                                                                                                        ty: !
+                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(16)), backwards_incompatible: None }
                                                                                                                                         span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
-                                                                                                                                        region_scope: Node(18)
-                                                                                                                                        safety_mode: Safe
-                                                                                                                                        stmts: [
-                                                                                                                                            Stmt {
-                                                                                                                                                kind: Expr {
-                                                                                                                                                    scope: Node(21)
-                                                                                                                                                    expr:
-                                                                                                                                                        Expr {
-                                                                                                                                                            ty: !
-                                                                                                                                                            temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
-                                                                                                                                                            span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0)
-                                                                                                                                                            kind: 
-                                                                                                                                                                Scope {
-                                                                                                                                                                    region_scope: Node(19)
-                                                                                                                                                                    lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19))
-                                                                                                                                                                    value:
-                                                                                                                                                                        Expr {
-                                                                                                                                                                            ty: !
-                                                                                                                                                                            temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
-                                                                                                                                                                            span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0)
-                                                                                                                                                                            kind: 
-                                                                                                                                                                                ConstContinue (
-                                                                                                                                                                                    label: Node(10)
-                                                                                                                                                                                    value:
-                                                                                                                                                                                        Expr {
-                                                                                                                                                                                            ty: bool
-                                                                                                                                                                                            temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
-                                                                                                                                                                                            span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0)
-                                                                                                                                                                                            kind: 
-                                                                                                                                                                                                Scope {
-                                                                                                                                                                                                    region_scope: Node(20)
-                                                                                                                                                                                                    lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20))
-                                                                                                                                                                                                    value:
-                                                                                                                                                                                                        Expr {
-                                                                                                                                                                                                            ty: bool
-                                                                                                                                                                                                            temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
-                                                                                                                                                                                                            span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0)
-                                                                                                                                                                                                            kind: 
-                                                                                                                                                                                                                Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) }, neg: false)
+                                                                                                                                        kind: 
+                                                                                                                                            Block {
+                                                                                                                                                targeted_by_break: false
+                                                                                                                                                span: $DIR/thir-tree-loop-match.rs:12:25: 15:18 (#0)
+                                                                                                                                                region_scope: Node(18)
+                                                                                                                                                safety_mode: Safe
+                                                                                                                                                stmts: [
+                                                                                                                                                    Stmt {
+                                                                                                                                                        kind: Expr {
+                                                                                                                                                            scope: Node(21)
+                                                                                                                                                            expr:
+                                                                                                                                                                Expr {
+                                                                                                                                                                    ty: !
+                                                                                                                                                                    temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
+                                                                                                                                                                    span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0)
+                                                                                                                                                                    kind: 
+                                                                                                                                                                        Scope {
+                                                                                                                                                                            region_scope: Node(19)
+                                                                                                                                                                            lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).19))
+                                                                                                                                                                            value:
+                                                                                                                                                                                Expr {
+                                                                                                                                                                                    ty: !
+                                                                                                                                                                                    temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
+                                                                                                                                                                                    span: $DIR/thir-tree-loop-match.rs:14:21: 14:37 (#0)
+                                                                                                                                                                                    kind: 
+                                                                                                                                                                                        ConstContinue (
+                                                                                                                                                                                            label: Node(10)
+                                                                                                                                                                                            value:
+                                                                                                                                                                                                Expr {
+                                                                                                                                                                                                    ty: bool
+                                                                                                                                                                                                    temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
+                                                                                                                                                                                                    span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0)
+                                                                                                                                                                                                    kind: 
+                                                                                                                                                                                                        Scope {
+                                                                                                                                                                                                            region_scope: Node(20)
+                                                                                                                                                                                                            lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).20))
+                                                                                                                                                                                                            value:
+                                                                                                                                                                                                                Expr {
+                                                                                                                                                                                                                    ty: bool
+                                                                                                                                                                                                                    temp_lifetime: TempLifetime { temp_lifetime: Some(Node(21)), backwards_incompatible: None }
+                                                                                                                                                                                                                    span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0)
+                                                                                                                                                                                                                    kind: 
+                                                                                                                                                                                                                        Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-loop-match.rs:14:32: 14:37 (#0) }, neg: false)
 
+                                                                                                                                                                                                                }
                                                                                                                                                                                                         }
                                                                                                                                                                                                 }
-                                                                                                                                                                                        }
-                                                                                                                                                                                )
+                                                                                                                                                                                        )
+                                                                                                                                                                                }
                                                                                                                                                                         }
                                                                                                                                                                 }
                                                                                                                                                         }
-                                                                                                                                                }
+                                                                                                                                                    }
+                                                                                                                                                ]
+                                                                                                                                                expr: []
                                                                                                                                             }
-                                                                                                                                        ]
-                                                                                                                                        expr: []
                                                                                                                                     }
                                                                                                                             }
                                                                                                                     }
                                                                                                             }
                                                                                                     }
+                                                                                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16))
+                                                                                                scope: Node(16)
+                                                                                                span: $DIR/thir-tree-loop-match.rs:12:17: 15:18 (#0)
                                                                                             }
-                                                                                        lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).16))
-                                                                                        scope: Node(16)
-                                                                                        span: $DIR/thir-tree-loop-match.rs:12:17: 15:18 (#0)
-                                                                                    }
-                                                                                    Arm {
-                                                                                        pattern: 
-                                                                                            Pat: {
-                                                                                                ty: bool
-                                                                                                span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0)
-                                                                                                kind: PatKind {
-                                                                                                    Constant {
-                                                                                                        value: Ty(bool, false)
+                                                                                            Arm {
+                                                                                                pattern: 
+                                                                                                    Pat: {
+                                                                                                        ty: bool
+                                                                                                        span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0)
+                                                                                                        kind: PatKind {
+                                                                                                            Constant {
+                                                                                                                value: Ty(bool, false)
+                                                                                                            }
+                                                                                                        }
                                                                                                     }
-                                                                                                }
-                                                                                            }
-                                                                                        guard: None
-                                                                                        body: 
-                                                                                            Expr {
-                                                                                                ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
-                                                                                                span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
-                                                                                                kind: 
-                                                                                                    Scope {
-                                                                                                        region_scope: Node(25)
-                                                                                                        lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25))
-                                                                                                        value:
-                                                                                                            Expr {
-                                                                                                                ty: bool
-                                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
-                                                                                                                span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
-                                                                                                                kind: 
-                                                                                                                    NeverToAny {
-                                                                                                                        source:
-                                                                                                                            Expr {
-                                                                                                                                ty: !
-                                                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
-                                                                                                                                span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
-                                                                                                                                kind: 
-                                                                                                                                    Return {
-                                                                                                                                        value:
-                                                                                                                                            Expr {
-                                                                                                                                                ty: bool
-                                                                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
-                                                                                                                                                span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0)
-                                                                                                                                                kind: 
-                                                                                                                                                    Scope {
-                                                                                                                                                        region_scope: Node(26)
-                                                                                                                                                        lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26))
-                                                                                                                                                        value:
-                                                                                                                                                            Expr {
-                                                                                                                                                                ty: bool
-                                                                                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
-                                                                                                                                                                span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0)
-                                                                                                                                                                kind: 
-                                                                                                                                                                    VarRef {
-                                                                                                                                                                        id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2))
+                                                                                                guard: None
+                                                                                                body: 
+                                                                                                    Expr {
+                                                                                                        ty: bool
+                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                        span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
+                                                                                                        kind: 
+                                                                                                            Scope {
+                                                                                                                region_scope: Node(25)
+                                                                                                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).25))
+                                                                                                                value:
+                                                                                                                    Expr {
+                                                                                                                        ty: bool
+                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                        span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
+                                                                                                                        kind: 
+                                                                                                                            NeverToAny {
+                                                                                                                                source:
+                                                                                                                                    Expr {
+                                                                                                                                        ty: !
+                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                                        span: $DIR/thir-tree-loop-match.rs:16:26: 16:38 (#0)
+                                                                                                                                        kind: 
+                                                                                                                                            Return {
+                                                                                                                                                value:
+                                                                                                                                                    Expr {
+                                                                                                                                                        ty: bool
+                                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                                                        span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0)
+                                                                                                                                                        kind: 
+                                                                                                                                                            Scope {
+                                                                                                                                                                region_scope: Node(26)
+                                                                                                                                                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).26))
+                                                                                                                                                                value:
+                                                                                                                                                                    Expr {
+                                                                                                                                                                        ty: bool
+                                                                                                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                                                                                        span: $DIR/thir-tree-loop-match.rs:16:33: 16:38 (#0)
+                                                                                                                                                                        kind: 
+                                                                                                                                                                            VarRef {
+                                                                                                                                                                                id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2))
+                                                                                                                                                                            }
                                                                                                                                                                     }
                                                                                                                                                             }
                                                                                                                                                     }
@@ -250,12 +274,12 @@ body:
                                                                                                                     }
                                                                                                             }
                                                                                                     }
+                                                                                                lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24))
+                                                                                                scope: Node(24)
+                                                                                                span: $DIR/thir-tree-loop-match.rs:16:17: 16:38 (#0)
                                                                                             }
-                                                                                        lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).24))
-                                                                                        scope: Node(24)
-                                                                                        span: $DIR/thir-tree-loop-match.rs:16:17: 16:38 (#0)
+                                                                                        ]
                                                                                     }
-                                                                                ]
                                                                             }
                                                                     }
                                                             }
diff --git a/tests/ui/traits/const-traits/const-via-item-bound.rs b/tests/ui/traits/const-traits/const-via-item-bound.rs
new file mode 100644
index 00000000000..23f122b7413
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-via-item-bound.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Bar {}
+
+trait Baz: const Bar {}
+
+trait Foo {
+    // Well-formedenss of `Baz` requires `<Self as Foo>::Bar: const Bar`.
+    // Make sure we assemble a candidate for that via the item bounds.
+    type Bar: Baz;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/dyn-trait.rs b/tests/ui/traits/dyn-trait.rs
index 4fb7aea5cba..a378ce5a696 100644
--- a/tests/ui/traits/dyn-trait.rs
+++ b/tests/ui/traits/dyn-trait.rs
@@ -7,7 +7,7 @@ static BYTE: u8 = 33;
 fn main() {
     let x: &(dyn 'static + Display) = &BYTE;
     let y: Box<dyn Display + 'static> = Box::new(BYTE);
-    let _: &dyn (Display) = &BYTE;
+    let _: &dyn Display = &BYTE;
     let _: &dyn (::std::fmt::Display) = &BYTE;
     let xstr = format!("{}", x);
     let ystr = format!("{}", y);
diff --git a/tests/ui/traits/impl-2.rs b/tests/ui/traits/impl-2.rs
index 41fa1cd334f..eafbaeaa167 100644
--- a/tests/ui/traits/impl-2.rs
+++ b/tests/ui/traits/impl-2.rs
@@ -10,7 +10,7 @@ pub mod Foo {
 }
 
 mod Bar {
-    impl<'a> dyn (crate::Foo::Trait) + 'a {
+    impl<'a> dyn crate::Foo::Trait + 'a {
         fn bar(&self) { self.foo() }
     }
 }
diff --git a/tests/ui/traits/negative-bounds/negative-sized.rs b/tests/ui/traits/negative-bounds/negative-sized.rs
new file mode 100644
index 00000000000..18369c78427
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-sized.rs
@@ -0,0 +1,8 @@
+#![feature(negative_bounds)]
+
+fn foo<T: !Sized>() {}
+
+fn main() {
+    foo::<()>();
+    //~^ ERROR the trait bound `(): !Sized` is not satisfied
+}
diff --git a/tests/ui/traits/negative-bounds/negative-sized.stderr b/tests/ui/traits/negative-bounds/negative-sized.stderr
new file mode 100644
index 00000000000..143933803b8
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-sized.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `(): !Sized` is not satisfied
+  --> $DIR/negative-sized.rs:6:11
+   |
+LL |     foo::<()>();
+   |           ^^ the trait bound `(): !Sized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-sized.rs:3:11
+   |
+LL | fn foo<T: !Sized>() {}
+   |           ^^^^^^ required by this bound in `foo`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/typeck/auxiliary/private-dep.rs b/tests/ui/typeck/auxiliary/private-dep.rs
new file mode 100644
index 00000000000..472b40ef622
--- /dev/null
+++ b/tests/ui/typeck/auxiliary/private-dep.rs
@@ -0,0 +1,3 @@
+pub trait A {
+    fn foo() {}
+}
diff --git a/tests/ui/typeck/auxiliary/public-dep.rs b/tests/ui/typeck/auxiliary/public-dep.rs
new file mode 100644
index 00000000000..438692a1caa
--- /dev/null
+++ b/tests/ui/typeck/auxiliary/public-dep.rs
@@ -0,0 +1,11 @@
+//@ aux-crate:priv:private_dep=private-dep.rs
+//@ compile-flags: -Zunstable-options
+
+extern crate private_dep;
+use private_dep::A;
+
+pub struct B;
+
+impl A for B {
+    fn foo() {}
+}
diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.rs b/tests/ui/typeck/dont-suggest-private-dependencies.rs
new file mode 100644
index 00000000000..ee5224e2d82
--- /dev/null
+++ b/tests/ui/typeck/dont-suggest-private-dependencies.rs
@@ -0,0 +1,37 @@
+// Don't suggest importing a function from a private dependency.
+// Issues: #138191, #142676
+
+// Avoid suggesting traits from std-private deps
+//@ forbid-output: compiler_builtins
+//@ forbid-output: object
+
+// Check a custom trait to withstand changes in above crates
+//@ aux-crate:public_dep=public-dep.rs
+//@ compile-flags: -Zunstable-options
+//@ forbid-output: private_dep
+
+// By default, the `read` diagnostic suggests `std::os::unix::fs::FileExt::read_at`. Add
+// something more likely to be recommended to make the diagnostic cross-platform.
+trait DecoyRead {
+    fn read1(&self) {}
+}
+impl<T> DecoyRead for Vec<T> {}
+
+struct VecReader(Vec<u8>);
+
+impl std::io::Read for VecReader {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        self.0.read(buf)
+        //~^ ERROR no method named `read` found for struct `Vec<u8>`
+    }
+}
+
+extern crate public_dep;
+use public_dep::B;
+
+fn main() {
+    let _ = u8::cast_from_lossy(9);
+    //~^ ERROR no function or associated item named `cast_from_lossy` found for type `u8`
+    let _ = B::foo();
+    //~^ ERROR no function or associated item named `foo` found for struct `B`
+}
diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.stderr b/tests/ui/typeck/dont-suggest-private-dependencies.stderr
new file mode 100644
index 00000000000..b7b14ee6b9b
--- /dev/null
+++ b/tests/ui/typeck/dont-suggest-private-dependencies.stderr
@@ -0,0 +1,27 @@
+error[E0599]: no method named `read` found for struct `Vec<u8>` in the current scope
+  --> $DIR/dont-suggest-private-dependencies.rs:24:16
+   |
+LL |         self.0.read(buf)
+   |                ^^^^
+   |
+help: there is a method `read1` with a similar name, but with different arguments
+  --> $DIR/dont-suggest-private-dependencies.rs:16:5
+   |
+LL |     fn read1(&self) {}
+   |     ^^^^^^^^^^^^^^^
+
+error[E0599]: no function or associated item named `cast_from_lossy` found for type `u8` in the current scope
+  --> $DIR/dont-suggest-private-dependencies.rs:33:17
+   |
+LL |     let _ = u8::cast_from_lossy(9);
+   |                 ^^^^^^^^^^^^^^^ function or associated item not found in `u8`
+
+error[E0599]: no function or associated item named `foo` found for struct `B` in the current scope
+  --> $DIR/dont-suggest-private-dependencies.rs:35:16
+   |
+LL |     let _ = B::foo();
+   |                ^^^ function or associated item not found in `B`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/underscore-lifetime/in-binder.stderr b/tests/ui/underscore-lifetime/in-binder.stderr
index fcd7eddb576..f25db4d0889 100644
--- a/tests/ui/underscore-lifetime/in-binder.stderr
+++ b/tests/ui/underscore-lifetime/in-binder.stderr
@@ -3,36 +3,48 @@ error[E0637]: `'_` cannot be used here
    |
 LL | impl<'_> IceCube<'_> {}
    |      ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:12:15
    |
 LL | struct Struct<'_> {
    |               ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:17:11
    |
 LL | enum Enum<'_> {
    |           ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:22:13
    |
 LL | union Union<'_> {
    |             ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:27:13
    |
 LL | trait Trait<'_> {
    |             ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/in-binder.rs:31:8
    |
 LL | fn foo<'_>() {
    |        ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
index d940166e9e2..50359309c92 100644
--- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
+++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
@@ -15,12 +15,16 @@ error[E0637]: `'_` cannot be used here
    |
 LL | fn foo<'_>
    |        ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0637]: `'_` cannot be used here
   --> $DIR/underscore-lifetime-binders.rs:10:25
    |
 LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
    |                         ^^ `'_` is a reserved lifetime name
+   |
+   = help: use another lifetime specifier
 
 error[E0106]: missing lifetime specifier
   --> $DIR/underscore-lifetime-binders.rs:10:33
diff --git a/triagebot.toml b/triagebot.toml
index 6385528e7b6..64a8a7c46b4 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1,6 +1,11 @@
 # This file's format is documented at
 # https://forge.rust-lang.org/triagebot/pr-assignment.html#configuration
 
+
+# ------------------------------------------------------------------------------
+# Labels
+# ------------------------------------------------------------------------------
+
 [relabel]
 allow-unauthenticated = [
     "A-*",
@@ -44,6 +49,11 @@ remove_labels = ["S-waiting-on-author"]
 # Those labels are added when PR author requests a review from an assignee
 add_labels = ["S-waiting-on-review"]
 
+
+# ------------------------------------------------------------------------------
+# Ping groups
+# ------------------------------------------------------------------------------
+
 [ping.windows]
 message = """\
 Hey Windows Group! This bug has been identified as a good "Windows candidate".
@@ -153,6 +163,11 @@ Hi relnotes-interest-group, this issue/PR could use some help in reviewing /
 adjusting release notes. Could you take a look if available? Thanks <3
 """
 
+
+# ------------------------------------------------------------------------------
+# Autolabels
+# ------------------------------------------------------------------------------
+
 [prioritize]
 label = "I-prioritize"
 
@@ -582,6 +597,11 @@ trigger_files = [
     "compiler/rustc_codegen_llvm",
 ]
 
+
+# ------------------------------------------------------------------------------
+# Prioritization and team nominations
+# ------------------------------------------------------------------------------
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/prioritization/alerts
 topic = "#{number} {title}"
@@ -598,6 +618,21 @@ message_on_remove = "Issue #{number}'s prioritization request has been removed."
 message_on_close = "Issue #{number} has been closed while requested for prioritization."
 message_on_reopen = "Issue #{number} has been reopened."
 
+[notify-zulip."I-types-nominated"]
+zulip_stream = 326866 # #T-types/nominated
+topic = "#{number}: {title}"
+message_on_add = """\
+@*T-types* issue #{number} "{title}" has been nominated for team discussion.
+"""
+message_on_remove = "Issue #{number}'s nomination has been removed. Thanks all for participating!"
+message_on_close = "Issue #{number} has been closed. Thanks for participating!"
+message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*."
+
+
+# ------------------------------------------------------------------------------
+# Zulip notifications
+# ------------------------------------------------------------------------------
+
 [notify-zulip."beta-nominated".rustdoc]
 required_labels = ["T-rustdoc"]
 zulip_stream = 266220 # #t-rustdoc
@@ -661,15 +696,6 @@ message_on_remove = "PR #{number}'s stable-acceptance has been **removed**."
 message_on_close = "PR #{number} has been closed. Thanks for participating!"
 message_on_reopen = "PR #{number} has been reopened. Pinging @*T-rustdoc*."
 
-[notify-zulip."I-types-nominated"]
-zulip_stream = 326866 # #T-types/nominated
-topic = "#{number}: {title}"
-message_on_add = """\
-@*T-types* issue #{number} "{title}" has been nominated for team discussion.
-"""
-message_on_remove = "Issue #{number}'s nomination has been removed. Thanks all for participating!"
-message_on_close = "Issue #{number} has been closed. Thanks for participating!"
-message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*."
 
 [notify-zulip."beta-nominated".compiler]
 required_labels = ["T-compiler"]
@@ -688,6 +714,13 @@ don't know
 ]
 message_on_remove = "PR #{number}'s beta-nomination has been removed."
 
+[notify-zulip."beta-accepted".compiler]
+required_labels = ["T-compiler"]
+zulip_stream = 474880 # #t-compiler/backports
+# Put it in the same thread as beta-nominated.
+topic = "#{number}: beta-nominated"
+message_on_add = "PR #{number} has been **accepted** for **beta** backport."
+
 [notify-zulip."stable-nominated".compiler]
 required_labels = ["T-compiler"]
 zulip_stream = 474880 # #t-compiler/backports
@@ -706,6 +739,14 @@ don't know
 ]
 message_on_remove = "PR #{number}'s stable-nomination has been removed."
 
+[notify-zulip."stable-accepted".compiler]
+required_labels = ["T-compiler"]
+zulip_stream = 474880 # #t-compiler/backports
+# Put it in the same thread as stable-nominated.
+topic = "#{number}: stable-nominated"
+message_on_add = "PR #{number} has been **accepted** for **stable** backport."
+
+
 [notify-zulip."beta-nominated".bootstrap]
 required_labels = ["T-bootstrap"]
 zulip_stream = 507486 # #t-infra/bootstrap/backports
@@ -723,6 +764,13 @@ don't know
 ]
 message_on_remove = "PR #{number}'s beta-nomination has been removed."
 
+[notify-zulip."beta-accepted".bootstrap]
+required_labels = ["T-bootstrap"]
+zulip_stream = 507486 # #t-infra/bootstrap/backports
+# Put it in the same thread as beta-nominated.
+topic = "#{number}: beta-nominated"
+message_on_add = "PR #{number} has been **accepted** for **beta** backport."
+
 [notify-zulip."stable-nominated".bootstrap]
 required_labels = ["T-bootstrap"]
 zulip_stream = 507486 # #t-infra/bootstrap/backports
@@ -741,6 +789,14 @@ don't know
 ]
 message_on_remove = "PR #{number}'s stable-nomination has been removed."
 
+[notify-zulip."stable-accepted".bootstrap]
+required_labels = ["T-bootstrap"]
+zulip_stream = 507486 # #t-infra/bootstrap/backports
+# Put it in the same thread as stable-nominated.
+topic = "#{number}: stable-nominated"
+message_on_add = "PR #{number} has been **accepted** for **stable** backport."
+
+
 [notify-zulip."A-edition-2021"]
 required_labels = ["C-bug"]
 zulip_stream = 268952 # #edition
@@ -757,17 +813,10 @@ message_on_add = """\
 Issue #{number} "{title}" has been added.
 """
 
-[no-merges]
-exclude_titles = ["Rollup of", "subtree update", "Subtree update"]
-labels = ["has-merge-commits", "S-waiting-on-author"]
-
-[github-releases]
-format = "rustc"
-project-name = "Rust"
-changelog-path = "RELEASES.md"
-changelog-branch = "master"
 
-[shortcut]
+# ------------------------------------------------------------------------------
+# Mentions
+# ------------------------------------------------------------------------------
 
 [mentions."triagebot.toml"]
 message = "`triagebot.toml` has been modified, there may have been changes to the review queue."
@@ -1201,6 +1250,11 @@ cc = ["@m-ou-se"]
 [mentions."compiler/rustc_ast_lowering/src/format.rs"]
 cc = ["@m-ou-se"]
 
+
+# ------------------------------------------------------------------------------
+# PR assignments
+# ------------------------------------------------------------------------------
+
 [assign]
 warn_non_default_branch.enable = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
@@ -1442,6 +1496,23 @@ compiletest = [
 
 [pr-tracking]
 
+
+# ------------------------------------------------------------------------------
+# Misc
+# ------------------------------------------------------------------------------
+
+[no-merges]
+exclude_titles = ["Rollup of", "subtree update", "Subtree update"]
+labels = ["has-merge-commits", "S-waiting-on-author"]
+
+[github-releases]
+format = "rustc"
+project-name = "Rust"
+changelog-path = "RELEASES.md"
+changelog-branch = "master"
+
+[shortcut]
+
 # Enable issue transfers within the org
 # Documentation at: https://forge.rust-lang.org/triagebot/transfer.html
 [transfer]
diff --git a/typos.toml b/typos.toml
new file mode 100644
index 00000000000..4035f206a46
--- /dev/null
+++ b/typos.toml
@@ -0,0 +1,74 @@
+[files]
+extend-exclude = [
+    # exclude git (sub)modules and generated content
+    "compiler/rustc_codegen_gcc",
+    "compiler/rustc_codegen_cranelift",
+    "compiler/rustc_baked_icu_data",
+    "library/compiler-builtins",
+    "library/backtrace",
+    "library/stdarch",
+    # generated lorem ipsum texts
+    "library/alloctests/benches/str.rs",
+    "library/alloctests/tests/str.rs",
+]
+
+[default.extend-words]
+# Add exclusions here, lines should be like `x = "x"`, where `x` is excluded word.
+#
+# Also see docs: https://github.com/crate-ci/typos/blob/v1.28.2/docs/reference.md
+rplace = "rplace"
+arange = "arange"
+unstalled = "unstalled"
+taits = "taits"
+Datas = "Datas"
+splitted = "splitted"
+leafs = "leafs"
+makro = "makro"
+optin = "optin"
+unparseable = "unparseable"
+smove = "smove"
+childs = "childs"
+filetimes = "filetimes"
+misformed = "misformed"
+targetting = "targetting"
+publically = "publically"
+clonable = "clonable"
+
+# this can be valid word, depends on dictionary edition
+#matcheable = "matcheable"
+
+[default.extend-identifiers]
+# An entry goes here if the typo is part of some existing ident
+# where you want to keep it, but don't want to allow
+# such typos everywhere.
+#
+# I.e. you don't want (or can't) fix some constant name, like
+# `DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME` but actually
+# want to see `INVAILD` typo fixed in other places.
+ERROR_FILENAME_EXCED_RANGE = "ERROR_FILENAME_EXCED_RANGE"
+DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME = "DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME"
+ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS = "ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS"
+ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC"
+ERROR_MCA_OCCURED = "ERROR_MCA_OCCURED"
+ERRNO_ACCES = "ERRNO_ACCES"
+tolen = "tolen"
+numer = "numer"
+
+[default]
+extend-ignore-words-re = [
+    # words with length <= 4 chars is likely noise
+    "^[a-zA-Z]{1,4}$",
+]
+
+extend-ignore-re = [
+    # ignore these intentional typo examples
+    "/// 1 \\| #\\[cfg\\(widnows\\)\\]",
+    "/// warning: unexpected `cfg` condition name: `widnows`",
+    "/// #\\[cfg\\(widnows\\)\\]",
+    "\\.arg\\(\"Oh no, a tpyo!\"\\)",
+    # string used in benches
+    "\"core::iter::adapters::Copie\"",
+    "-Ccontrol-flow-guard",
+    "concat!\\(\"CURRENT_RUSTC_VERSIO\", \"N\"\\)",
+    "\\*\\*v\\*\\*ariable"
+]