about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock14
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs20
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/crate_level.rs36
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/debugger.rs60
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs63
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs18
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/util.rs37
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/lints.rs12
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs7
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs16
-rw-r--r--compiler/rustc_codegen_gcc/src/base.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs9
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs196
-rw-r--r--compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs2
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs4
-rw-r--r--compiler/rustc_const_eval/messages.ftl14
-rw-r--r--compiler/rustc_const_eval/src/errors.rs17
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs46
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs18
-rw-r--r--compiler/rustc_const_eval/src/util/caller_location.rs2
-rw-r--r--compiler/rustc_expand/src/base.rs6
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs25
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs45
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs6
-rw-r--r--compiler/rustc_hir/src/attrs/data_structures.rs25
-rw-r--r--compiler/rustc_hir/src/attrs/encode_cross_crate.rs3
-rw-r--r--compiler/rustc_hir/src/lints.rs35
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs192
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs72
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs6
-rw-r--r--compiler/rustc_interface/messages.ftl2
-rw-r--r--compiler/rustc_interface/src/passes.rs3
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_interface/src/util.rs8
-rw-r--r--compiler/rustc_lexer/src/lib.rs4
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs10
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs7
-rw-r--r--compiler/rustc_llvm/Cargo.toml3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp4
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp18
-rw-r--r--compiler/rustc_macros/src/query.rs2
-rw-r--r--compiler/rustc_metadata/messages.ftl7
-rw-r--r--compiler/rustc_metadata/src/creader.rs4
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs47
-rw-r--r--compiler/rustc_metadata/src/errors.rs10
-rw-r--r--compiler/rustc_middle/messages.ftl6
-rw-r--r--compiler/rustc_middle/src/error.rs6
-rw-r--r--compiler/rustc_middle/src/middle/debugger_visualizer.rs8
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs1
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs7
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs34
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/ty/util.rs11
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs24
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs3
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs9
-rw-r--r--compiler/rustc_mir_transform/src/impossible_predicates.rs33
-rw-r--r--compiler/rustc_mir_transform/src/patch.rs36
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs3
-rw-r--r--compiler/rustc_passes/messages.ftl16
-rw-r--r--compiler/rustc_passes/src/check_attr.rs77
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs113
-rw-r--r--compiler/rustc_passes/src/errors.rs26
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs19
-rw-r--r--compiler/rustc_resolve/src/ident.rs11
-rw-r--r--compiler/rustc_resolve/src/imports.rs26
-rw-r--r--compiler/rustc_resolve/src/lib.rs128
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_session/src/config.rs10
-rw-r--r--compiler/rustc_session/src/config/cfg.rs11
-rw-r--r--compiler/rustc_session/src/options.rs7
-rw-r--r--compiler/rustc_session/src/session.rs10
-rw-r--r--compiler/rustc_span/src/symbol.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs14
-rw-r--r--compiler/rustc_target/src/asm/mod.rs5
-rw-r--r--compiler/rustc_target/src/asm/powerpc.rs12
-rw-r--r--compiler/rustc_target/src/spec/base/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/base/motor.rs34
-rw-r--r--compiler/rustc_target/src/spec/base/wasm.rs5
-rw-r--r--compiler/rustc_target/src/spec/base/windows_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/crt_objects.rs17
-rw-r--r--compiler/rustc_target/src/spec/mod.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs38
-rw-r--r--compiler/rustc_thread_pool/src/latch.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs11
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs6
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs1
-rw-r--r--compiler/rustc_ty_utils/src/errors.rs13
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs26
-rw-r--r--compiler/rustc_windows_rc/Cargo.toml4
-rw-r--r--compiler/rustc_windows_rc/src/lib.rs34
-rw-r--r--library/Cargo.lock10
-rw-r--r--library/alloc/Cargo.toml2
-rw-r--r--library/alloc/src/alloc.rs4
-rw-r--r--library/alloc/src/collections/btree/map.rs3
-rw-r--r--library/alloc/src/collections/btree/node.rs17
-rw-r--r--library/alloc/src/ffi/c_str.rs7
-rw-r--r--library/alloc/src/raw_vec/mod.rs151
-rw-r--r--library/alloc/src/raw_vec/tests.rs10
-rw-r--r--library/alloc/src/rc.rs9
-rw-r--r--library/alloc/src/sync.rs9
-rw-r--r--library/alloc/src/vec/extract_if.rs64
-rw-r--r--library/alloc/src/vec/mod.rs40
-rw-r--r--library/alloctests/tests/lib.rs2
-rw-r--r--library/alloctests/tests/vec.rs15
-rw-r--r--library/compiler-builtins/libm/src/math/support/float_traits.rs2
-rw-r--r--library/core/Cargo.toml2
-rw-r--r--library/core/src/ascii/ascii_char.rs2
-rw-r--r--library/core/src/cell.rs4
-rw-r--r--library/core/src/error.rs8
-rw-r--r--library/core/src/ffi/c_str.rs4
-rw-r--r--library/core/src/intrinsics/mod.rs154
-rw-r--r--library/core/src/iter/adapters/flatten.rs2
-rw-r--r--library/core/src/num/f128.rs30
-rw-r--r--library/core/src/num/f16.rs30
-rw-r--r--library/core/src/num/f32.rs33
-rw-r--r--library/core/src/num/f64.rs33
-rw-r--r--library/core/src/num/int_macros.rs6
-rw-r--r--library/core/src/num/mod.rs4
-rw-r--r--library/core/src/num/nonzero.rs12
-rw-r--r--library/core/src/num/uint_macros.rs4
-rw-r--r--library/core/src/option.rs8
-rw-r--r--library/core/src/panicking.rs83
-rw-r--r--library/core/src/result.rs4
-rw-r--r--library/core/src/slice/index.rs6
-rw-r--r--library/core/src/slice/mod.rs4
-rw-r--r--library/core/src/slice/sort/shared/smallsort.rs4
-rw-r--r--library/core/src/str/mod.rs4
-rw-r--r--library/core/src/ub_checks.rs5
-rw-r--r--library/coretests/tests/atomic.rs244
-rw-r--r--library/coretests/tests/floats/f128.rs18
-rw-r--r--library/coretests/tests/floats/f16.rs18
-rw-r--r--library/coretests/tests/floats/f32.rs21
-rw-r--r--library/coretests/tests/floats/f64.rs21
-rw-r--r--library/coretests/tests/floats/mod.rs242
-rw-r--r--library/coretests/tests/fmt/mod.rs6
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/std/Cargo.toml12
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/env.rs2
-rw-r--r--library/std/src/io/mod.rs2
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/net/socket_addr.rs2
-rw-r--r--library/std/src/num/f128.rs16
-rw-r--r--library/std/src/num/f16.rs16
-rw-r--r--library/std/src/num/f32.rs19
-rw-r--r--library/std/src/num/f64.rs19
-rw-r--r--library/std/src/panicking.rs26
-rw-r--r--library/std/src/path.rs12
-rw-r--r--library/std/src/process.rs13
-rw-r--r--library/std/src/rt.rs4
-rw-r--r--library/std/src/sync/nonpoison/mutex.rs2
-rw-r--r--library/std/src/sync/nonpoison/rwlock.rs2
-rw-r--r--library/std/src/sync/poison/mutex.rs2
-rw-r--r--library/std/src/sync/poison/rwlock.rs2
-rw-r--r--library/std/src/sync/reentrant_lock.rs2
-rw-r--r--library/std/src/sys/alloc/mod.rs3
-rw-r--r--library/std/src/sys/alloc/vexos.rs96
-rw-r--r--library/std/src/sys/env_consts.rs11
-rw-r--r--library/std/src/sys/fs/mod.rs4
-rw-r--r--library/std/src/sys/fs/vexos.rs615
-rw-r--r--library/std/src/sys/pal/hermit/time.rs11
-rw-r--r--library/std/src/sys/pal/mod.rs4
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs4
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs2
-rw-r--r--library/std/src/sys/pal/unix/time.rs27
-rw-r--r--library/std/src/sys/pal/vexos/mod.rs80
-rw-r--r--library/std/src/sys/pal/vexos/time.rs28
-rw-r--r--library/std/src/sys/process/mod.rs2
-rw-r--r--library/std/src/sys/process/uefi.rs9
-rw-r--r--library/std/src/sys/process/unix/common.rs9
-rw-r--r--library/std/src/sys/process/unix/fuchsia.rs1
-rw-r--r--library/std/src/sys/process/unix/mod.rs2
-rw-r--r--library/std/src/sys/process/unix/unix.rs1
-rw-r--r--library/std/src/sys/process/unix/unsupported.rs1
-rw-r--r--library/std/src/sys/process/unix/vxworks.rs1
-rw-r--r--library/std/src/sys/process/unsupported.rs9
-rw-r--r--library/std/src/sys/process/windows.rs7
-rw-r--r--library/std/src/sys/random/mod.rs2
-rw-r--r--library/std/src/sys/stdio/mod.rs4
-rw-r--r--library/std/src/sys/stdio/vexos.rs100
-rw-r--r--library/std/src/sys/thread/mod.rs7
-rw-r--r--library/std/src/sys/thread/vexos.rs17
-rw-r--r--library/std/src/sys/thread_local/mod.rs2
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--library/std/tests/path.rs16
-rw-r--r--library/std/tests/time.rs16
-rw-r--r--library/std_detect/src/detect/os/darwin/aarch64.rs22
-rw-r--r--library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs12
-rw-r--r--library/stdarch/crates/core_arch/src/wasm32/mod.rs16
-rw-r--r--library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml12
-rw-r--r--library/sysroot/Cargo.toml1
-rw-r--r--src/bootstrap/bootstrap.py2
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs16
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs6
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs2
-rw-r--r--src/bootstrap/src/core/builder/mod.rs4
-rw-r--r--src/bootstrap/src/core/builder/tests.rs49
-rw-r--r--src/bootstrap/src/core/config/config.rs72
-rw-r--r--src/bootstrap/src/core/config/tests.rs548
-rw-r--r--src/bootstrap/src/core/config/toml/mod.rs4
-rw-r--r--src/bootstrap/src/core/download.rs18
-rw-r--r--src/bootstrap/src/core/sanity.rs5
-rw-r--r--src/bootstrap/src/lib.rs28
-rw-r--r--src/bootstrap/src/utils/build_stamp.rs2
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs10
-rw-r--r--src/bootstrap/src/utils/exec.rs6
-rw-r--r--src/bootstrap/src/utils/helpers/tests.rs11
-rw-r--r--src/bootstrap/src/utils/render_tests.rs2
-rw-r--r--src/bootstrap/src/utils/tarball.rs2
-rw-r--r--src/bootstrap/src/utils/tests/mod.rs53
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile2
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile2
-rw-r--r--src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile2
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh7
m---------src/doc/book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/SUMMARY.md1
-rw-r--r--src/doc/rustc-dev-guide/src/about-this-guide.md8
-rw-r--r--src/doc/rustc-dev-guide/src/appendix/glossary.md1
-rw-r--r--src/doc/rustc-dev-guide/src/autodiff/type-trees.md193
-rw-r--r--src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md26
-rw-r--r--src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md2
-rw-r--r--src/doc/rustc-dev-guide/src/compiler-team.md4
-rw-r--r--src/doc/rustc-dev-guide/src/fuzzing.md7
-rw-r--r--src/doc/rustc-dev-guide/src/profiling/with_perf.md3
-rw-r--r--src/doc/rustc-dev-guide/src/tests/best-practices.md4
-rw-r--r--src/doc/rustc-dev-guide/src/tests/ci.md111
-rw-r--r--src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md57
-rw-r--r--src/doc/rustc-dev-guide/src/tests/compiletest.md8
-rw-r--r--src/doc/rustc-dev-guide/src/tests/crater.md24
-rw-r--r--src/doc/rustc-dev-guide/src/tracing.md2
-rw-r--r--src/doc/rustc/src/SUMMARY.md9
-rw-r--r--src/doc/rustc/src/codegen-options/index.md2
-rw-r--r--src/doc/rustc/src/linker-plugin-lto.md7
-rw-r--r--src/doc/rustc/src/platform-support.md5
-rw-r--r--src/doc/rustc/src/platform-support/arm-linux.md217
-rw-r--r--src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armebv7r-none-eabi.md2
-rw-r--r--src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md3
-rw-r--r--src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md3
-rw-r--r--src/doc/rustc/src/platform-support/armv7a-vex-v5.md26
-rw-r--r--src/doc/rustc/src/platform-support/motor.md45
-rw-r--r--src/doc/rustc/src/symbol-mangling/v0.md28
-rw-r--r--src/doc/rustdoc/src/advanced-features.md20
-rw-r--r--src/doc/rustdoc/src/unstable-features.md26
-rw-r--r--src/doc/unstable-book/src/compiler-flags/branch-protection.md1
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md6
-rw-r--r--src/librustdoc/clean/cfg.rs78
-rw-r--r--src/librustdoc/clean/types.rs112
-rw-r--r--src/librustdoc/display.rs86
-rw-r--r--src/librustdoc/html/format.rs348
-rw-r--r--src/librustdoc/html/highlight.rs250
-rw-r--r--src/librustdoc/html/markdown.rs45
-rw-r--r--src/librustdoc/html/render/mod.rs187
-rw-r--r--src/librustdoc/html/render/print_item.rs8
-rw-r--r--src/librustdoc/html/render/search_index.rs23
-rw-r--r--src/librustdoc/html/render/span_map.rs124
-rw-r--r--src/librustdoc/html/render/write_shared.rs9
-rw-r--r--src/librustdoc/html/static/js/main.js25
-rw-r--r--src/librustdoc/html/templates/type_layout.html5
-rw-r--r--src/librustdoc/json/conversions.rs9
-rw-r--r--src/librustdoc/lib.rs7
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs3
-rw-r--r--src/librustdoc/passes/strip_hidden.rs5
-rw-r--r--src/librustdoc/visit_ast.rs10
m---------src/llvm-project0
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs7
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.stdout32
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.stdout28
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.fixed2
-rw-r--r--src/tools/clippy/tests/ui/useless_attribute.rs2
-rw-r--r--src/tools/compiletest/Cargo.toml2
-rw-r--r--src/tools/compiletest/src/directives.rs19
-rw-r--r--src/tools/compiletest/src/directives/directive_names.rs1
-rw-r--r--src/tools/compiletest/src/runtest.rs24
-rw-r--r--src/tools/features-status-dump/src/main.rs3
-rw-r--r--src/tools/miri/.github/workflows/ci.yml39
-rw-r--r--src/tools/miri/miri-script/src/commands.rs8
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs6
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs28
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs102
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs101
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs10
-rw-r--r--src/tools/miri/src/concurrency/sync.rs4
-rw-r--r--src/tools/miri/src/intrinsics/math.rs41
-rw-r--r--src/tools/miri/src/machine.rs5
-rw-r--r--src/tools/miri/tests/fail/async-shared-mutable.tree.stderr2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr4
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs3
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs2
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/unique.default.stderr32
-rw-r--r--src/tools/miri/tests/pass/0weak_memory/weak.rs33
-rw-r--r--src/tools/miri/tests/pass/float.rs198
-rw-r--r--src/tools/miri/tests/pass/float_nan.rs37
-rw-r--r--src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs103
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs2
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs4
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/reserved.rs4
-rw-r--r--src/tools/miri/tests/pass/vec.rs10
-rw-r--r--src/tools/miri/tests/utils/mod.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs4
-rw-r--r--src/tools/rustfmt/src/config/mod.rs1
-rw-r--r--src/tools/tidy/src/alphabetical.rs31
-rw-r--r--src/tools/tidy/src/alphabetical/tests.rs27
-rw-r--r--src/tools/tidy/src/bins.rs14
-rw-r--r--src/tools/tidy/src/debug_artifacts.rs15
-rw-r--r--src/tools/tidy/src/deps.rs117
-rw-r--r--src/tools/tidy/src/diagnostics.rs243
-rw-r--r--src/tools/tidy/src/edition.rs9
-rw-r--r--src/tools/tidy/src/error_codes.rs124
-rw-r--r--src/tools/tidy/src/extdeps.rs9
-rw-r--r--src/tools/tidy/src/extra_checks/mod.rs7
-rw-r--r--src/tools/tidy/src/features.rs132
-rw-r--r--src/tools/tidy/src/filenames.rs20
-rw-r--r--src/tools/tidy/src/fluent_alphabetical.rs36
-rw-r--r--src/tools/tidy/src/fluent_lowercase.rs13
-rw-r--r--src/tools/tidy/src/fluent_period.rs13
-rw-r--r--src/tools/tidy/src/fluent_used.rs7
-rw-r--r--src/tools/tidy/src/gcc_submodule.rs13
-rw-r--r--src/tools/tidy/src/known_bug.rs9
-rw-r--r--src/tools/tidy/src/lib.rs51
-rw-r--r--src/tools/tidy/src/main.rs49
-rw-r--r--src/tools/tidy/src/mir_opt_tests.rs23
-rw-r--r--src/tools/tidy/src/pal.rs11
-rw-r--r--src/tools/tidy/src/rustdoc_css_themes.rs37
-rw-r--r--src/tools/tidy/src/rustdoc_gui_tests.rs11
-rw-r--r--src/tools/tidy/src/rustdoc_json.rs46
-rw-r--r--src/tools/tidy/src/rustdoc_templates.rs15
-rw-r--r--src/tools/tidy/src/style.rs37
-rw-r--r--src/tools/tidy/src/target_policy.rs7
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs23
-rw-r--r--src/tools/tidy/src/tests_placement.rs17
-rw-r--r--src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs16
-rw-r--r--src/tools/tidy/src/triagebot.rs38
-rw-r--r--src/tools/tidy/src/ui_tests.rs53
-rw-r--r--src/tools/tidy/src/unit_tests.rs14
-rw-r--r--src/tools/tidy/src/unknown_revision.rs17
-rw-r--r--src/tools/tidy/src/unstable_book.rs40
-rw-r--r--src/tools/tidy/src/x_version.rs17
-rw-r--r--src/tools/unstable-book-gen/src/main.rs3
-rw-r--r--tests/assembly-llvm/aarch64-pointer-auth.rs6
-rw-r--r--tests/assembly-llvm/targets/targets-elf.rs3
-rw-r--r--tests/codegen-llvm/asm/powerpc-clobbers.rs8
-rw-r--r--tests/codegen-llvm/asm/readonly-not-pure.rs48
-rw-r--r--tests/codegen-llvm/branch-protection.rs6
-rw-r--r--tests/codegen-llvm/global-allocator-attributes.rs41
-rw-r--r--tests/codegen-llvm/intrinsic-no-unnamed-attr.rs4
-rw-r--r--tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs17
-rw-r--r--tests/codegen-llvm/pattern_type_symbols.rs4
-rw-r--r--tests/coverage/issue-83601.cov-map34
-rw-r--r--tests/coverage/issue-84561.cov-map136
-rw-r--r--tests/crashes/117808.rs27
-rw-r--r--tests/crashes/122904-2.rs17
-rw-r--r--tests/crashes/139556.rs13
-rw-r--r--tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml12
-rw-r--r--tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs65
-rw-r--r--tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs46
-rw-r--r--tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml4
-rw-r--r--tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs1
-rw-r--r--tests/run-make-cargo/panic-immediate-abort-works/rmake.rs39
-rw-r--r--tests/run-make/crate-loading/dep-2-reexport.rs (renamed from tests/run-make/crate-loading/multiple-dep-versions-3.rs)0
-rw-r--r--tests/run-make/crate-loading/dependency-1.rs (renamed from tests/run-make/crate-loading/multiple-dep-versions-1.rs)0
-rw-r--r--tests/run-make/crate-loading/dependency-2.rs (renamed from tests/run-make/crate-loading/multiple-dep-versions-2.rs)0
-rw-r--r--tests/run-make/crate-loading/rmake.rs9
-rw-r--r--tests/run-make/linker-warning/rmake.rs1
-rw-r--r--tests/run-make/musl-default-linking/rmake.rs3
-rw-r--r--tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs8
-rw-r--r--tests/run-make/pointer-auth-link-with-c/rmake.rs10
-rw-r--r--tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs28
-rw-r--r--tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs1
-rw-r--r--tests/rustdoc-gui/search-title.goml12
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs9
-rw-r--r--tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs25
-rw-r--r--tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr38
-rw-r--r--tests/rustdoc/attribute-rendering.rs8
-rw-r--r--tests/rustdoc/attributes.rs12
-rw-r--r--tests/rustdoc/auxiliary/ext-repr.rs5
-rw-r--r--tests/rustdoc/inline_cross/attributes.rs17
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/attributes.rs9
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/repr.rs42
-rw-r--r--tests/rustdoc/inline_cross/repr.rs40
-rw-r--r--tests/rustdoc/jump-to-def-assoc-items.rs54
-rw-r--r--tests/rustdoc/jump-to-def-ice-assoc-types.rs20
-rw-r--r--tests/rustdoc/jump-to-def-ice.rs24
-rw-r--r--tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs4
-rw-r--r--tests/rustdoc/jump-to-def/jump-to-def-pats.rs10
-rw-r--r--tests/rustdoc/jump-to-def/jump-to-non-local-method.rs7
-rw-r--r--tests/rustdoc/reexport/auxiliary/reexports-attrs.rs14
-rw-r--r--tests/rustdoc/reexport/private-mod-override-reexport.rs13
-rw-r--r--tests/rustdoc/reexport/reexport-attrs.rs20
-rw-r--r--tests/rustdoc/repr.rs154
-rw-r--r--tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs2
-rw-r--r--tests/ui/asm/powerpc/bad-reg.aix64.stderr162
-rw-r--r--tests/ui/asm/powerpc/bad-reg.powerpc.stderr176
-rw-r--r--tests/ui/asm/powerpc/bad-reg.powerpc64.stderr168
-rw-r--r--tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr162
-rw-r--r--tests/ui/asm/powerpc/bad-reg.rs30
-rw-r--r--tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs17
-rw-r--r--tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr34
-rw-r--r--tests/ui/attributes/invalid_macro_export_argument.allow.stderr40
-rw-r--r--tests/ui/attributes/invalid_macro_export_argument.deny.stderr93
-rw-r--r--tests/ui/attributes/invalid_macro_export_argument.rs12
-rw-r--r--tests/ui/attributes/malformed-attrs.rs5
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr73
-rw-r--r--tests/ui/check-cfg/cfg-crate-features.stderr2
-rw-r--r--tests/ui/check-cfg/report-in-external-macros.cargo.stderr2
-rw-r--r--tests/ui/check-cfg/report-in-external-macros.rustc.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr6
-rw-r--r--tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg4
-rw-r--r--tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg4
-rw-r--r--tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs46
-rw-r--r--tests/ui/const-generics/adt_const_params/unsized_field-1.stderr6
-rw-r--r--tests/ui/const-generics/forbid-non-structural_match-types.stderr2
-rw-r--r--tests/ui/const-generics/issue-80471.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-97278.stderr4
-rw-r--r--tests/ui/consts/const-eval/ub-nonnull.rs4
-rw-r--r--tests/ui/consts/const-eval/ub-nonnull.stderr17
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.rs23
-rw-r--r--tests/ui/consts/const-eval/ub-ref-ptr.stderr67
-rw-r--r--tests/ui/consts/const_transmute_type_id7.rs16
-rw-r--r--tests/ui/consts/const_transmute_type_id7.stderr14
-rw-r--r--tests/ui/consts/promoted_const_call2.rs1
-rw-r--r--tests/ui/consts/promoted_const_call2.stderr17
-rw-r--r--tests/ui/consts/refs_check_const_eq-issue-88384.stderr4
-rw-r--r--tests/ui/coroutine/copy-fast-path-query-cycle.rs40
-rw-r--r--tests/ui/coroutine/moved-twice.rs (renamed from tests/crashes/122630.rs)11
-rw-r--r--tests/ui/coroutine/moved-twice.stderr24
-rw-r--r--tests/ui/diagnostic-flags/colored-session-opt-error.svg4
-rw-r--r--tests/ui/diagnostic-flags/terminal_urls.rs4
-rw-r--r--tests/ui/diagnostic-flags/terminal_urls.stderr11
-rw-r--r--tests/ui/diagnostic-flags/terminal_urls.svg48
-rw-r--r--tests/ui/diagnostic-flags/terminal_urls.windows.svg49
-rw-r--r--tests/ui/error-emitter/E0308-clarification.svg2
-rw-r--r--tests/ui/error-emitter/highlighting.svg2
-rw-r--r--tests/ui/error-emitter/highlighting.windows.svg2
-rw-r--r--tests/ui/error-emitter/multiline-multipart-suggestion.svg2
-rw-r--r--tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg2
-rw-r--r--tests/ui/error-emitter/multiline-removal-suggestion.svg4
-rw-r--r--tests/ui/error-emitter/unicode-output.svg2
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs3
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr79
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs30
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr389
-rw-r--r--tests/ui/frontmatter/unclosed-6.rs12
-rw-r--r--tests/ui/frontmatter/unclosed-6.stderr19
-rw-r--r--tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs12
-rw-r--r--tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr17
-rw-r--r--tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg4
-rw-r--r--tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr6
-rw-r--r--tests/ui/intrinsics/intrinsic-fmuladd.rs4
-rw-r--r--tests/ui/intrinsics/reify-intrinsic.stderr2
-rw-r--r--tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr2
-rw-r--r--tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr2
-rw-r--r--tests/ui/invalid/invalid-debugger-visualizer-option.rs2
-rw-r--r--tests/ui/invalid/invalid-debugger-visualizer-option.stderr22
-rw-r--r--tests/ui/invalid/invalid-debugger-visualizer-target.rs3
-rw-r--r--tests/ui/invalid/invalid-debugger-visualizer-target.stderr4
-rw-r--r--tests/ui/issues/issue-27592.stderr12
-rw-r--r--tests/ui/iterators/issue-58952-filter-type-length.rs2
-rw-r--r--tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs19
-rw-r--r--tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr8
-rw-r--r--tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs6
-rw-r--r--tests/ui/lint/unused/unused-attr-duplicate.stderr24
-rw-r--r--tests/ui/panic-runtime/auxiliary/needs-abort.rs2
-rw-r--r--tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs7
-rw-r--r--tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs18
-rw-r--r--tests/ui/panic-runtime/bad-panic-flag1.rs2
-rw-r--r--tests/ui/panic-runtime/bad-panic-flag1.stderr2
-rw-r--r--tests/ui/panic-runtime/bad-panic-flag2.rs2
-rw-r--r--tests/ui/panic-runtime/bad-panic-flag2.stderr2
-rw-r--r--tests/ui/panic-runtime/immediate-abort-default-sysroot.rs15
-rw-r--r--tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr4
-rw-r--r--tests/ui/panic-runtime/need-abort-got-immediate-abort.rs21
-rw-r--r--tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr4
-rw-r--r--tests/ui/panic-runtime/need-immediate-abort-got-abort.rs20
-rw-r--r--tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr4
-rw-r--r--tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs20
-rw-r--r--tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr4
-rw-r--r--tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs21
-rw-r--r--tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr4
-rw-r--r--tests/ui/proc-macro/panic-abort.rs2
-rw-r--r--tests/ui/proc-macro/panic-abort.stderr2
-rw-r--r--tests/ui/resolve/unused-macro-import.rs13
-rw-r--r--tests/ui/resolve/unused-macro-import.stderr14
-rw-r--r--tests/ui/simd/auxiliary/simd-lane-limit.rs5
-rw-r--r--tests/ui/simd/monomorphize-too-long.rs4
-rw-r--r--tests/ui/simd/monomorphize-too-long.stderr6
-rw-r--r--tests/ui/simd/monomorphize-zero-length.rs4
-rw-r--r--tests/ui/simd/monomorphize-zero-length.stderr6
-rw-r--r--tests/ui/simd/simd-lane-limit-err-npow2.rs12
-rw-r--r--tests/ui/simd/simd-lane-limit-err-npow2.stderr8
-rw-r--r--tests/ui/simd/simd-lane-limit-err.rs11
-rw-r--r--tests/ui/simd/simd-lane-limit-err.stderr8
-rw-r--r--tests/ui/simd/simd-lane-limit-ok.rs14
-rw-r--r--tests/ui/simd/type-generic-monomorphisation-empty.rs4
-rw-r--r--tests/ui/simd/type-generic-monomorphisation-empty.stderr6
-rw-r--r--tests/ui/simd/type-generic-monomorphisation-oversized.rs5
-rw-r--r--tests/ui/simd/type-generic-monomorphisation-oversized.stderr6
-rw-r--r--tests/ui/suggestions/incorrect-variant-literal.svg2
-rw-r--r--tests/ui/suggestions/issue-97760.stderr7
-rw-r--r--tests/ui/suggestions/non_copy_move_out_of_tuple.rs8
-rw-r--r--tests/ui/suggestions/non_copy_move_out_of_tuple.stderr26
-rw-r--r--tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs2
-rw-r--r--tests/ui/traits/next-solver/writeback-predicate-bound-region.rs14
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs19
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr30
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs24
-rw-r--r--tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr58
-rw-r--r--tests/ui/type-alias-impl-trait/type-error-drop-elaboration.rs (renamed from tests/crashes/125185.rs)3
-rw-r--r--tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr12
-rw-r--r--tests/ui/type-inference/box_has_sigdrop.rs9
-rw-r--r--tests/ui/type-inference/box_has_sigdrop.stderr17
-rw-r--r--tests/ui/type-inference/dropper_has_sigdrop.rs (renamed from tests/ui/type-inference/has_sigdrop.rs)0
-rw-r--r--tests/ui/unpretty/exhaustive.hir.stdout3
-rw-r--r--tests/ui/unpretty/flattened-format-args.stdout3
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr2
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr2
-rw-r--r--tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr2
581 files changed, 9372 insertions, 4804 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c2e635b4cfe..3d4a1bf6a78 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,9 +128,9 @@ dependencies = [
 
 [[package]]
 name = "anstyle-svg"
-version = "0.1.10"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc03a770ef506fe1396c0e476120ac0e6523cf14b74218dd5f18cd6833326fa9"
+checksum = "26b9ec8c976eada1b0f9747a3d7cc4eae3bef10613e443746e7487f26c872fde"
 dependencies = [
  "anstyle",
  "anstyle-lossy",
@@ -1333,6 +1333,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "find-msvc-tools"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959"
+
+[[package]]
 name = "flate2"
 version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3556,7 +3562,7 @@ dependencies = [
  "ar_archive_writer",
  "bitflags",
  "bstr",
- "cc",
+ "find-msvc-tools",
  "itertools",
  "libc",
  "object 0.37.3",
@@ -4760,7 +4766,7 @@ dependencies = [
 name = "rustc_windows_rc"
 version = "0.0.0"
 dependencies = [
- "cc",
+ "find-msvc-tools",
 ]
 
 [[package]]
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index ec9d26eb33f..2871430030c 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -487,26 +487,6 @@ fn expand_format_args<'hir>(
         // Generate:
         //     []
         (vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[]))))
-    } else if argmap.len() == 1 && arguments.len() == 1 {
-        // Only one argument, so we don't need to make the `args` tuple.
-        //
-        // Generate:
-        //     super let args = [<core::fmt::Argument>::new_display(&arg)];
-        let args = ctx.arena.alloc_from_iter(argmap.iter().map(
-            |(&(arg_index, ty), &placeholder_span)| {
-                let arg = &arguments[arg_index];
-                let placeholder_span =
-                    placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
-                let arg = ctx.lower_expr(&arg.expr);
-                let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg));
-                make_argument(ctx, placeholder_span, ref_arg, ty)
-            },
-        ));
-        let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
-        let args_ident = Ident::new(sym::args, macsp);
-        let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
-        let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
-        (vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)))
     } else {
         // Generate:
         //     super let args = (&arg0, &arg1, &…);
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 0a340cd5e93..20ec0fd0c7b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -1,40 +1,4 @@
-use std::num::IntErrorKind;
-
-use rustc_hir::limit::Limit;
-
 use super::prelude::*;
-use crate::session_diagnostics::LimitInvalid;
-
-impl<S: Stage> AcceptContext<'_, '_, S> {
-    fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
-        let Some(limit) = nv.value_as_str() else {
-            self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
-            return None;
-        };
-
-        let error_str = match limit.as_str().parse() {
-            Ok(i) => return Some(Limit::new(i)),
-            Err(e) => match e.kind() {
-                IntErrorKind::PosOverflow => "`limit` is too large",
-                IntErrorKind::Empty => "`limit` must be a non-negative integer",
-                IntErrorKind::InvalidDigit => "not a valid integer",
-                IntErrorKind::NegOverflow => {
-                    panic!(
-                        "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
-                    )
-                }
-                IntErrorKind::Zero => {
-                    panic!("zero is a valid `limit` so should have returned Ok() when parsing")
-                }
-                kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
-            },
-        };
-
-        self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
-
-        None
-    }
-}
 
 pub(crate) struct CrateNameParser;
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
new file mode 100644
index 00000000000..56ff10be426
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs
@@ -0,0 +1,60 @@
+use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType};
+
+use super::prelude::*;
+
+pub(crate) struct DebuggerViualizerParser;
+
+impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser {
+    const PATH: &[Symbol] = &[sym::debugger_visualizer];
+    const ALLOWED_TARGETS: AllowedTargets =
+        AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
+    const TEMPLATE: AttributeTemplate = template!(
+        List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
+        "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
+    );
+
+    type Item = DebugVisualizer;
+    const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v);
+
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'c {
+        let Some(l) = args.list() else {
+            cx.expected_list(args.span().unwrap_or(cx.attr_span));
+            return None;
+        };
+        let Some(single) = l.single() else {
+            cx.expected_single_argument(l.span);
+            return None;
+        };
+        let Some(mi) = single.meta_item() else {
+            cx.expected_name_value(single.span(), None);
+            return None;
+        };
+        let path = mi.path().word_sym();
+        let visualizer_type = match path {
+            Some(sym::natvis_file) => DebuggerVisualizerType::Natvis,
+            Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter,
+            _ => {
+                cx.expected_specific_argument(
+                    mi.path().span(),
+                    &[sym::natvis_file, sym::gdb_script_file],
+                );
+                return None;
+            }
+        };
+
+        let Some(path) = mi.args().name_value() else {
+            cx.expected_name_value(single.span(), path);
+            return None;
+        };
+
+        let Some(path) = path.value_as_str() else {
+            cx.expected_string_literal(path.value_span, Some(path.value_as_lit()));
+            return None;
+        };
+
+        Some(DebugVisualizer { span: mi.span(), visualizer_type, path })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
index 180130c7be4..849141c34f7 100644
--- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
@@ -1,3 +1,4 @@
+use rustc_ast::AttrStyle;
 use rustc_errors::DiagArgValue;
 use rustc_hir::attrs::MacroUseArgs;
 
@@ -133,3 +134,65 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
     ]);
     const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
 }
+
+pub(crate) struct MacroExportParser;
+
+impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
+    const PATH: &[Symbol] = &[sym::macro_export];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const TEMPLATE: AttributeTemplate = template!(Word, List: &["local_inner_macros"]);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
+        Allow(Target::MacroDef),
+        Error(Target::WherePredicate),
+        Error(Target::Crate),
+    ]);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let suggestions = || {
+            <Self as SingleAttributeParser<S>>::TEMPLATE
+                .suggestions(AttrStyle::Inner, "macro_export")
+        };
+        let local_inner_macros = match args {
+            ArgParser::NoArgs => false,
+            ArgParser::List(list) => {
+                let Some(l) = list.single() else {
+                    let span = cx.attr_span;
+                    cx.emit_lint(
+                        AttributeLintKind::InvalidMacroExportArguments {
+                            suggestions: suggestions(),
+                        },
+                        span,
+                    );
+                    return None;
+                };
+                match l.meta_item().and_then(|i| i.path().word_sym()) {
+                    Some(sym::local_inner_macros) => true,
+                    _ => {
+                        let span = cx.attr_span;
+                        cx.emit_lint(
+                            AttributeLintKind::InvalidMacroExportArguments {
+                                suggestions: suggestions(),
+                            },
+                            span,
+                        );
+                        return None;
+                    }
+                }
+            }
+            ArgParser::NameValue(_) => {
+                let span = cx.attr_span;
+                let suggestions = suggestions();
+                cx.emit_err(IllFormedAttributeInputLint {
+                    num_suggestions: suggestions.len(),
+                    suggestions: DiagArgValue::StrListSepByAnd(
+                        suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
+                    ),
+                    span,
+                });
+                return None;
+            }
+        };
+        Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 4ed13d239b9..8dbf4c0ef32 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -36,6 +36,7 @@ pub(crate) mod cfg_old;
 pub(crate) mod codegen_attrs;
 pub(crate) mod confusables;
 pub(crate) mod crate_level;
+pub(crate) mod debugger;
 pub(crate) mod deprecation;
 pub(crate) mod dummy;
 pub(crate) mod inline;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index a995549fc7c..cf2f5c6c790 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -49,3 +49,21 @@ impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
         Some(AttributeKind::RustcObjectLifetimeDefault)
     }
 }
+
+pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
+    const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let ArgParser::NameValue(nv) = args else {
+            cx.expected_name_value(cx.attr_span, None);
+            return None;
+        };
+        Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs
index 77e8c32e59d..62b72798e96 100644
--- a/compiler/rustc_attr_parsing/src/attributes/util.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/util.rs
@@ -1,11 +1,15 @@
+use std::num::IntErrorKind;
+
 use rustc_ast::LitKind;
 use rustc_ast::attr::AttributeExt;
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::RustcVersion;
+use rustc_hir::limit::Limit;
 use rustc_span::{Symbol, sym};
 
 use crate::context::{AcceptContext, Stage};
-use crate::parser::ArgParser;
+use crate::parser::{ArgParser, NameValueParser};
+use crate::session_diagnostics::LimitInvalid;
 
 /// Parse a rustc version number written inside string literal in an attribute,
 /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
@@ -85,3 +89,34 @@ pub(crate) fn parse_single_integer<S: Stage>(
     };
     Some(num.0)
 }
+
+impl<S: Stage> AcceptContext<'_, '_, S> {
+    pub(crate) fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
+        let Some(limit) = nv.value_as_str() else {
+            self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
+            return None;
+        };
+
+        let error_str = match limit.as_str().parse() {
+            Ok(i) => return Some(Limit::new(i)),
+            Err(e) => match e.kind() {
+                IntErrorKind::PosOverflow => "`limit` is too large",
+                IntErrorKind::Empty => "`limit` must be a non-negative integer",
+                IntErrorKind::InvalidDigit => "not a valid integer",
+                IntErrorKind::NegOverflow => {
+                    panic!(
+                        "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
+                    )
+                }
+                IntErrorKind::Zero => {
+                    panic!("zero is a valid `limit` so should have returned Ok() when parsing")
+                }
+                kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
+            },
+        };
+
+        self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
+
+        None
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index ee5b7322b02..d7ccf3c7806 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -28,6 +28,7 @@ use crate::attributes::crate_level::{
     CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
     RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
 };
+use crate::attributes::debugger::DebuggerViualizerParser;
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::dummy::DummyParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -40,7 +41,7 @@ use crate::attributes::lint_helpers::{
 };
 use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
 use crate::attributes::macro_attrs::{
-    AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
+    AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser,
 };
 use crate::attributes::must_use::MustUseParser;
 use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
@@ -53,7 +54,7 @@ use crate::attributes::prototype::CustomMirParser;
 use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
 use crate::attributes::rustc_internal::{
     RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
-    RustcObjectLifetimeDefaultParser,
+    RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
 };
 use crate::attributes::semantics::MayDangleParser;
 use crate::attributes::stability::{
@@ -163,6 +164,7 @@ attribute_parsers!(
         // tidy-alphabetical-start
         Combine<AllowConstFnUnstableParser>,
         Combine<AllowInternalUnstableParser>,
+        Combine<DebuggerViualizerParser>,
         Combine<ForceTargetFeatureParser>,
         Combine<LinkParser>,
         Combine<ReprParser>,
@@ -183,6 +185,7 @@ attribute_parsers!(
         Single<LinkOrdinalParser>,
         Single<LinkSectionParser>,
         Single<LinkageParser>,
+        Single<MacroExportParser>,
         Single<MoveSizeLimitParser>,
         Single<MustUseParser>,
         Single<ObjcClassParser>,
@@ -197,6 +200,7 @@ attribute_parsers!(
         Single<RustcLayoutScalarValidRangeEnd>,
         Single<RustcLayoutScalarValidRangeStart>,
         Single<RustcObjectLifetimeDefaultParser>,
+        Single<RustcSimdMonomorphizeLaneLimitParser>,
         Single<SanitizeParser>,
         Single<ShouldPanicParser>,
         Single<SkipDuringMethodDispatchParser>,
diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs
index b1a971eec32..ab8ba0daf1f 100644
--- a/compiler/rustc_attr_parsing/src/lints.rs
+++ b/compiler/rustc_attr_parsing/src/lints.rs
@@ -31,6 +31,18 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi
                 },
             );
         }
+        AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter
+            .emit_node_span_lint(
+                rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS,
+                *id,
+                *span,
+                session_diagnostics::IllFormedAttributeInput {
+                    num_suggestions: suggestions.len(),
+                    suggestions: DiagArgValue::StrListSepByAnd(
+                        suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
+                    ),
+                },
+            ),
         AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint(
             rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
             *id,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 5f4bfd9df48..0910e8ef4b3 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1736,9 +1736,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // `BoringNoLocation` constraints can point to user-written code, but are less
                 // specific, and are not used for relations that would make sense to blame.
                 ConstraintCategory::BoringNoLocation => 6,
-                // Do not blame internal constraints.
-                ConstraintCategory::OutlivesUnnameablePlaceholder(_) => 7,
-                ConstraintCategory::Internal => 8,
+                // Do not blame internal constraints if we can avoid it. Never blame
+                // the `'region: 'static` constraints introduced by placeholder outlives.
+                ConstraintCategory::Internal => 7,
+                ConstraintCategory::OutlivesUnnameablePlaceholder(_) => 8,
             };
 
             debug!("constraint {constraint:?} category: {category:?}, interest: {interest:?}");
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 19cbcd139aa..606d3d95d9e 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -505,6 +505,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let mut constraints = Default::default();
         let mut liveness_constraints =
             LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body)));
+        let mut deferred_closure_requirements = Default::default();
 
         // Don't try to add borrow_region facts for the promoted MIR as they refer
         // to the wrong locations.
@@ -512,6 +513,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             mem::swap(this.polonius_facts, polonius_facts);
             mem::swap(&mut this.constraints.outlives_constraints, &mut constraints);
             mem::swap(&mut this.constraints.liveness_constraints, &mut liveness_constraints);
+            mem::swap(this.deferred_closure_requirements, &mut deferred_closure_requirements);
         };
 
         swap_constraints(self);
@@ -536,6 +538,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
             self.constraints.outlives_constraints.push(constraint)
         }
+
+        // If there are nested bodies in promoteds, we also need to update their
+        // location to something in the actual body, not the promoted.
+        //
+        // We don't update the constraint categories of the resulting constraints
+        // as returns in nested bodies are a proper return, even if that nested body
+        // is in a promoted.
+        for (closure_def_id, args, _locations) in deferred_closure_requirements {
+            self.deferred_closure_requirements.push((closure_def_id, args, locations));
+        }
+
         // If the region is live at least one location in the promoted MIR,
         // then add a liveness constraint to the main MIR for this region
         // at the location provided as an argument to this method
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index f14b1920722..96bece2a368 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -85,7 +85,7 @@ impl AllocFnFactory<'_, '_> {
             body,
             define_opaque: None,
         }));
-        let item = self.cx.item(self.span, self.attrs(), kind);
+        let item = self.cx.item(self.span, self.attrs(method), kind);
         self.cx.stmt_item(self.ty_span, item)
     }
 
@@ -100,8 +100,18 @@ impl AllocFnFactory<'_, '_> {
         self.cx.expr_call(self.ty_span, method, args)
     }
 
-    fn attrs(&self) -> AttrVec {
-        thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)]
+    fn attrs(&self, method: &AllocatorMethod) -> AttrVec {
+        let alloc_attr = match method.name {
+            sym::alloc => sym::rustc_allocator,
+            sym::dealloc => sym::rustc_deallocator,
+            sym::realloc => sym::rustc_reallocator,
+            sym::alloc_zeroed => sym::rustc_allocator_zeroed,
+            _ => unreachable!("Unknown allocator method!"),
+        };
+        thin_vec![
+            self.cx.attr_word(sym::rustc_std_internal_symbol, self.span),
+            self.cx.attr_word(alloc_attr, self.span)
+        ]
     }
 
     fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> Box<Expr> {
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 51089e5a1d3..82c59d5a3a2 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -63,8 +63,8 @@ pub fn inject(
 
     if sess.is_test_crate() {
         let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
-            (PanicStrategy::Abort, true) => PanicStrategy::Abort,
-            (PanicStrategy::Abort, false) => {
+            (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, true) => panic_strategy,
+            (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, false) => {
                 if panic_strategy == platform_panic_strategy {
                     // Silently allow compiling with panic=abort on these platforms,
                     // but with old behavior (abort if a test fails).
@@ -287,10 +287,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
     let ecx = &cx.ext_cx;
     let test_ident = Ident::new(sym::test, sp);
 
-    let runner_name = match cx.panic_strategy {
-        PanicStrategy::Unwind => "test_main_static",
-        PanicStrategy::Abort => "test_main_static_abort",
-    };
+    let runner_name =
+        if cx.panic_strategy.unwinds() { "test_main_static" } else { "test_main_static_abort" };
 
     // test::test_main_static(...)
     let mut test_runner = cx.test_runner.clone().unwrap_or_else(|| {
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 2fbe5c02802..81b1814605a 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -439,7 +439,10 @@ pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
 impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+        if let LayoutError::SizeOverflow(_)
+        | LayoutError::InvalidSimd { .. }
+        | LayoutError::ReferencesError(_) = err
+        {
             self.0.sess.dcx().span_fatal(span, err.to_string())
         } else {
             self.0
@@ -458,7 +461,9 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
         span: Span,
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
-        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
+            err
+        {
             self.0.sess.dcx().emit_fatal(Spanned { span, node: err })
         } else {
             match fn_abi_request {
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index 203b443269f..1306c6aa517 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -42,7 +42,10 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
 impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+        if let LayoutError::SizeOverflow(_)
+        | LayoutError::InvalidSimd { .. }
+        | LayoutError::ReferencesError(_) = err
+        {
             self.tcx.sess.dcx().span_fatal(span, err.to_string())
         } else {
             self.tcx
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 17e2e028b16..a14881c502c 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -698,8 +698,12 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str {
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
-        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
-        | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+        InlineAsmRegClass::PowerPC(
+            PowerPCInlineAsmRegClass::cr
+            | PowerPCInlineAsmRegClass::ctr
+            | PowerPCInlineAsmRegClass::lr
+            | PowerPCInlineAsmRegClass::xer,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
@@ -777,8 +781,12 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
             cx.type_vector(cx.type_i32(), 4)
         }
-        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
-        | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+        InlineAsmRegClass::PowerPC(
+            PowerPCInlineAsmRegClass::cr
+            | PowerPCInlineAsmRegClass::ctr
+            | PowerPCInlineAsmRegClass::lr
+            | PowerPCInlineAsmRegClass::xer,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index e9d72e457a0..e8672f49580 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -15,9 +15,9 @@ use rustc_middle::mir::mono::Visibility;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::DebugInfo;
 use rustc_span::Symbol;
+use rustc_target::spec::RelocModel;
 #[cfg(feature = "master")]
 use rustc_target::spec::SymbolVisibility;
-use rustc_target::spec::{PanicStrategy, RelocModel};
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
@@ -101,7 +101,7 @@ pub fn compile_codegen_unit(
         // Instantiate monomorphizations without filling out definitions yet...
         let context = new_context(tcx);
 
-        if tcx.sess.panic_strategy() == PanicStrategy::Unwind {
+        if tcx.sess.panic_strategy().unwinds() {
             context.add_command_line_option("-fexceptions");
             context.add_driver_option("-fexceptions");
         }
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 665cf22ddba..9815fb07eaa 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -529,7 +529,10 @@ impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
 impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+        if let LayoutError::SizeOverflow(_)
+        | LayoutError::InvalidSimd { .. }
+        | LayoutError::ReferencesError(_) = err
+        {
             self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic()))
         } else {
             self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
@@ -545,7 +548,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
         span: Span,
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
-        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
+            err
+        {
             self.tcx.dcx().emit_fatal(respan(span, err))
         } else {
             match fn_abi_request {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 84fa56cf903..a915f5d6418 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -29,7 +29,6 @@ use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{Span, Symbol, sym};
 use rustc_target::callconv::{ArgAbi, PassMode};
-use rustc_target::spec::PanicStrategy;
 
 #[cfg(feature = "master")]
 use crate::abi::FnAbiGccExt;
@@ -1334,7 +1333,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(
     _catch_func: RValue<'gcc>,
     dest: PlaceRef<'tcx, RValue<'gcc>>,
 ) {
-    if bx.sess().panic_strategy() == PanicStrategy::Abort {
+    if !bx.sess().panic_strategy().unwinds() {
         bx.call(bx.type_void(), None, None, try_func, &[data], None, None);
         // Return 0 unconditionally from the intrinsic call;
         // we can never unwind.
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 11be7041167..861227f7c2a 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -538,7 +538,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
 
         // If the declaration has an associated instance, compute extra attributes based on that.
         if let Some(instance) = instance {
-            llfn_attrs_from_instance(cx, llfn, instance);
+            llfn_attrs_from_instance(
+                cx,
+                cx.tcx,
+                llfn,
+                &cx.tcx.codegen_instance_attrs(instance.def),
+                Some(instance),
+            );
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index df3e49279d9..abd63120397 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -5,15 +5,16 @@ use rustc_ast::expand::allocator::{
 };
 use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
 use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, OomStrategy};
 use rustc_symbol_mangling::mangle_internal_symbol;
-use smallvec::SmallVec;
 
+use crate::attributes::llfn_attrs_from_instance;
 use crate::builder::SBuilder;
 use crate::declare::declare_simple_fn;
 use crate::llvm::{self, FALSE, TRUE, Type, Value};
-use crate::{SimpleCx, attributes, debuginfo, llvm_util};
+use crate::{SimpleCx, attributes, debuginfo};
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
@@ -149,18 +150,8 @@ fn create_wrapper_function(
         ty,
     );
 
-    let mut attrs = SmallVec::<[_; 2]>::new();
-
-    let target_cpu = llvm_util::target_cpu(tcx.sess);
-    let target_cpu_attr = llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu);
-
-    let tune_cpu_attr = llvm_util::tune_cpu(tcx.sess)
-        .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu));
-
-    attrs.push(target_cpu_attr);
-    attrs.extend(tune_cpu_attr);
-
-    attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs);
+    let attrs = CodegenFnAttrs::new();
+    llfn_attrs_from_instance(cx, tcx, llfn, &attrs, None);
 
     let no_return = if no_return {
         // -> ! DIFlagNoReturn
@@ -171,12 +162,6 @@ fn create_wrapper_function(
         None
     };
 
-    if tcx.sess.must_emit_unwind_tables() {
-        let uwtable =
-            attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);
-        attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
-    }
-
     let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
     let mut bx = SBuilder::build(&cx, llbb);
 
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index b79176e9098..cc09fa5b69b 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -340,8 +340,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx));
         } else if options.contains(InlineAsmOptions::NOMEM) {
             attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx));
-        } else {
-            // LLVM doesn't have an attribute to represent ReadOnly + SideEffect
+        } else if options.contains(InlineAsmOptions::READONLY) {
+            attrs.push(llvm::MemoryEffects::ReadOnlyNotPure.create_attr(self.cx.llcx));
         }
         attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
 
@@ -662,7 +662,12 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
             PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
             PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
-            PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
+            PowerPC(
+                PowerPCInlineAsmRegClass::cr
+                | PowerPCInlineAsmRegClass::ctr
+                | PowerPCInlineAsmRegClass::lr
+                | PowerPCInlineAsmRegClass::xer,
+            ) => {
                 unreachable!("clobber-only")
             }
             RiscV(RiscVInlineAsmRegClass::reg) => "r",
@@ -830,7 +835,12 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
         PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
         PowerPC(PowerPCInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i32(), 4),
-        PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
+        PowerPC(
+            PowerPCInlineAsmRegClass::cr
+            | PowerPCInlineAsmRegClass::ctr
+            | PowerPCInlineAsmRegClass::lr
+            | PowerPCInlineAsmRegClass::xer,
+        ) => {
             unreachable!("clobber-only")
         }
         RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 573c51a9539..8070ea0b3e9 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -1,20 +1,21 @@
 //! Set and unset common attributes on LLVM values.
-use rustc_codegen_ssa::traits::*;
 use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_hir::def_id::DefId;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
+use rustc_middle::middle::codegen_fn_attrs::{
+    CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
+};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
 use rustc_symbol_mangling::mangle_internal_symbol;
 use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 use smallvec::SmallVec;
 
-use crate::context::CodegenCx;
+use crate::context::SimpleCx;
 use crate::errors::SanitizerMemtagRequiresMte;
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
 use crate::value::Value;
-use crate::{attributes, llvm_util};
+use crate::{Session, attributes, llvm_util};
 
 pub(crate) fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) {
     if !attrs.is_empty() {
@@ -30,18 +31,19 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
 
 /// Get LLVM attribute for the provided inline heuristic.
 pub(crate) fn inline_attr<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     instance: ty::Instance<'tcx>,
 ) -> Option<&'ll Attribute> {
     // `optnone` requires `noinline`
-    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
+    let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
     let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
         (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
-        (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
+        (InlineAttr::None, _) if instance.def.requires_inline(tcx) => InlineAttr::Hint,
         (inline, _) => inline,
     };
 
-    if !cx.tcx.sess.opts.unstable_opts.inline_llvm {
+    if !tcx.sess.opts.unstable_opts.inline_llvm {
         // disable LLVM inlining
         return Some(AttributeKind::NoInline.create_attr(cx.llcx));
     }
@@ -51,7 +53,7 @@ pub(crate) fn inline_attr<'ll, 'tcx>(
             Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
         }
         InlineAttr::Never => {
-            if cx.sess().target.arch != "amdgpu" {
+            if tcx.sess.target.arch != "amdgpu" {
                 Some(AttributeKind::NoInline.create_attr(cx.llcx))
             } else {
                 None
@@ -63,12 +65,13 @@ pub(crate) fn inline_attr<'ll, 'tcx>(
 
 #[inline]
 fn patchable_function_entry_attrs<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
     attr: Option<PatchableFunctionEntry>,
 ) -> SmallVec<[&'ll Attribute; 2]> {
     let mut attrs = SmallVec::new();
     let patchable_spec = attr.unwrap_or_else(|| {
-        PatchableFunctionEntry::from_config(cx.tcx.sess.opts.unstable_opts.patchable_function_entry)
+        PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry)
     });
     let entry = patchable_spec.entry();
     let prefix = patchable_spec.prefix();
@@ -91,12 +94,13 @@ fn patchable_function_entry_attrs<'ll>(
 
 /// Get LLVM sanitize attributes.
 #[inline]
-pub(crate) fn sanitize_attrs<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+pub(crate) fn sanitize_attrs<'ll, 'tcx>(
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     no_sanitize: SanitizerSet,
 ) -> SmallVec<[&'ll Attribute; 4]> {
     let mut attrs = SmallVec::new();
-    let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
+    let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
     if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
         attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
     }
@@ -114,11 +118,11 @@ pub(crate) fn sanitize_attrs<'ll>(
     }
     if enabled.contains(SanitizerSet::MEMTAG) {
         // Check to make sure the mte target feature is actually enabled.
-        let features = cx.tcx.global_backend_features(());
+        let features = tcx.global_backend_features(());
         let mte_feature =
             features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
         if let None | Some("-mte") = mte_feature {
-            cx.tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
+            tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
         }
 
         attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
@@ -139,9 +143,12 @@ pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>)
     llvm::CreateUWTableAttr(llcx, async_unwind)
 }
 
-pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    let mut fp = cx.sess().target.frame_pointer;
-    let opts = &cx.sess().opts;
+pub(crate) fn frame_pointer_type_attr<'ll>(
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
+) -> Option<&'ll Attribute> {
+    let mut fp = sess.target.frame_pointer;
+    let opts = &sess.opts;
     // "mcount" function relies on stack pointer.
     // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
     if opts.unstable_opts.instrument_mcount {
@@ -156,8 +163,8 @@ pub(crate) fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'
     Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
 }
 
-fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    let function_return_attr = match cx.sess().opts.unstable_opts.function_return {
+fn function_return_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    let function_return_attr = match sess.opts.unstable_opts.function_return {
         FunctionReturn::Keep => return None,
         FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern,
     };
@@ -167,17 +174,20 @@ fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute>
 
 /// Tell LLVM what instrument function to insert.
 #[inline]
-fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> {
+fn instrument_function_attr<'ll>(
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
+) -> SmallVec<[&'ll Attribute; 4]> {
     let mut attrs = SmallVec::new();
-    if cx.sess().opts.unstable_opts.instrument_mcount {
+    if sess.opts.unstable_opts.instrument_mcount {
         // Similar to `clang -pg` behavior. Handled by the
         // `post-inline-ee-instrument` LLVM pass.
 
         // The function name varies on platforms.
         // See test/CodeGen/mcount.c in clang.
-        let mcount_name = match &cx.sess().target.llvm_mcount_intrinsic {
+        let mcount_name = match &sess.target.llvm_mcount_intrinsic {
             Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
-            None => cx.sess().target.mcount.as_ref(),
+            None => sess.target.mcount.as_ref(),
         };
 
         attrs.push(llvm::CreateAttrStringValue(
@@ -186,7 +196,7 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr
             mcount_name,
         ));
     }
-    if let Some(options) = &cx.sess().opts.unstable_opts.instrument_xray {
+    if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
         // XRay instrumentation is similar to __cyg_profile_func_{enter,exit}.
         // Function prologue and epilogue are instrumented with NOP sleds,
         // a runtime library later replaces them with detours into tracing code.
@@ -217,20 +227,20 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attr
     attrs
 }
 
-fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    if !cx.sess().opts.unstable_opts.no_jump_tables {
+fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    if !sess.opts.unstable_opts.no_jump_tables {
         return None;
     }
 
     Some(llvm::CreateAttrStringValue(cx.llcx, "no-jump-tables", "true"))
 }
 
-fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
+fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&'ll Attribute> {
     // Currently stack probes seem somewhat incompatible with the address
     // sanitizer and thread sanitizer. With asan we're already protected from
     // stack overflow anyway so we don't really need stack probes regardless.
-    if cx
-        .sess()
+    if tcx
+        .sess
         .opts
         .unstable_opts
         .sanitizer
@@ -240,22 +250,22 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     }
 
     // probestack doesn't play nice either with `-C profile-generate`.
-    if cx.sess().opts.cg.profile_generate.enabled() {
+    if tcx.sess.opts.cg.profile_generate.enabled() {
         return None;
     }
 
-    let attr_value = match cx.sess().target.stack_probes {
+    let attr_value = match tcx.sess.target.stack_probes {
         StackProbeType::None => return None,
         // Request LLVM to generate the probes inline. If the given LLVM version does not support
         // this, no probe is generated at all (even if the attribute is specified).
         StackProbeType::Inline => "inline-asm",
         // Flag our internal `__rust_probestack` function as the stack probe symbol.
         // This is defined in the `compiler-builtins` crate for each architecture.
-        StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"),
+        StackProbeType::Call => &mangle_internal_symbol(tcx, "__rust_probestack"),
         // Pick from the two above based on the LLVM version.
         StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
             if llvm_util::get_version() < min_llvm_version_for_inline {
-                &mangle_internal_symbol(cx.tcx, "__rust_probestack")
+                &mangle_internal_symbol(tcx, "__rust_probestack")
             } else {
                 "inline-asm"
             }
@@ -264,8 +274,8 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value))
 }
 
-fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    let sspattr = match cx.sess().stack_protector() {
+fn stackprotector_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    let sspattr = match sess.stack_protector() {
         StackProtector::None => return None,
         StackProtector::All => AttributeKind::StackProtectReq,
         StackProtector::Strong => AttributeKind::StackProtectStrong,
@@ -275,33 +285,34 @@ fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
     Some(sspattr.create_attr(cx.llcx))
 }
 
-fn backchain_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    if cx.sess().target.arch != "s390x" {
+fn backchain_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    if sess.target.arch != "s390x" {
         return None;
     }
 
-    let requested_features = cx.sess().opts.cg.target_feature.split(',');
+    let requested_features = sess.opts.cg.target_feature.split(',');
     let found_positive = requested_features.clone().any(|r| r == "+backchain");
 
     if found_positive { Some(llvm::CreateAttrString(cx.llcx, "backchain")) } else { None }
 }
 
-pub(crate) fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute {
-    let target_cpu = llvm_util::target_cpu(cx.tcx.sess);
+pub(crate) fn target_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> &'ll Attribute {
+    let target_cpu = llvm_util::target_cpu(sess);
     llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
 }
 
-pub(crate) fn tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
-    llvm_util::tune_cpu(cx.tcx.sess)
+pub(crate) fn tune_cpu_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
+    llvm_util::tune_cpu(sess)
         .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
 }
 
 /// Get the `target-features` LLVM attribute.
-pub(crate) fn target_features_attr<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+pub(crate) fn target_features_attr<'ll, 'tcx>(
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     function_features: Vec<String>,
 ) -> Option<&'ll Attribute> {
-    let global_features = cx.tcx.global_backend_features(()).iter().map(String::as_str);
+    let global_features = tcx.global_backend_features(()).iter().map(String::as_str);
     let function_features = function_features.iter().map(String::as_str);
     let target_features =
         global_features.chain(function_features).intersperse(",").collect::<String>();
@@ -311,22 +322,22 @@ pub(crate) fn target_features_attr<'ll>(
 
 /// Get the `NonLazyBind` LLVM attribute,
 /// if the codegen options allow skipping the PLT.
-pub(crate) fn non_lazy_bind_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
+pub(crate) fn non_lazy_bind_attr<'ll>(
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
+) -> Option<&'ll Attribute> {
     // Don't generate calls through PLT if it's not necessary
-    if !cx.sess().needs_plt() {
-        Some(AttributeKind::NonLazyBind.create_attr(cx.llcx))
-    } else {
-        None
-    }
+    if !sess.needs_plt() { Some(AttributeKind::NonLazyBind.create_attr(cx.llcx)) } else { None }
 }
 
 /// Get the default optimizations attrs for a function.
 #[inline]
 pub(crate) fn default_optimisation_attrs<'ll>(
-    cx: &CodegenCx<'ll, '_>,
+    cx: &SimpleCx<'ll>,
+    sess: &Session,
 ) -> SmallVec<[&'ll Attribute; 2]> {
     let mut attrs = SmallVec::new();
-    match cx.sess().opts.optimize {
+    match sess.opts.optimize {
         OptLevel::Size => {
             attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
         }
@@ -347,17 +358,18 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
 /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
 /// attributes.
 pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
+    cx: &SimpleCx<'ll>,
+    tcx: TyCtxt<'tcx>,
     llfn: &'ll Value,
-    instance: ty::Instance<'tcx>,
+    codegen_fn_attrs: &CodegenFnAttrs,
+    instance: Option<ty::Instance<'tcx>>,
 ) {
-    let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def);
-
+    let sess = tcx.sess;
     let mut to_add = SmallVec::<[_; 16]>::new();
 
     match codegen_fn_attrs.optimize {
         OptimizeAttr::Default => {
-            to_add.extend(default_optimisation_attrs(cx));
+            to_add.extend(default_optimisation_attrs(cx, sess));
         }
         OptimizeAttr::DoNotOptimize => {
             to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
@@ -369,21 +381,21 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         OptimizeAttr::Speed => {}
     }
 
-    if cx.sess().must_emit_unwind_tables() {
-        to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind));
+    if sess.must_emit_unwind_tables() {
+        to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind));
     }
 
-    if cx.sess().opts.unstable_opts.profile_sample_use.is_some() {
+    if sess.opts.unstable_opts.profile_sample_use.is_some() {
         to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
     }
 
     // FIXME: none of these functions interact with source level attributes.
-    to_add.extend(frame_pointer_type_attr(cx));
-    to_add.extend(function_return_attr(cx));
-    to_add.extend(instrument_function_attr(cx));
-    to_add.extend(nojumptables_attr(cx));
-    to_add.extend(probestack_attr(cx));
-    to_add.extend(stackprotector_attr(cx));
+    to_add.extend(frame_pointer_type_attr(cx, sess));
+    to_add.extend(function_return_attr(cx, sess));
+    to_add.extend(instrument_function_attr(cx, sess));
+    to_add.extend(nojumptables_attr(cx, sess));
+    to_add.extend(probestack_attr(cx, tcx));
+    to_add.extend(stackprotector_attr(cx, sess));
 
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
         to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
@@ -404,16 +416,19 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         // not used.
     } else {
         // Do not set sanitizer attributes for naked functions.
-        to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
+        to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.no_sanitize));
 
         // For non-naked functions, set branch protection attributes on aarch64.
-        if let Some(BranchProtection { bti, pac_ret }) =
-            cx.sess().opts.unstable_opts.branch_protection
+        if let Some(BranchProtection { bti, pac_ret, gcs }) =
+            sess.opts.unstable_opts.branch_protection
         {
-            assert!(cx.sess().target.arch == "aarch64");
+            assert!(sess.target.arch == "aarch64");
             if bti {
                 to_add.push(llvm::CreateAttrString(cx.llcx, "branch-target-enforcement"));
             }
+            if gcs {
+                to_add.push(llvm::CreateAttrString(cx.llcx, "guarded-control-stack"));
+            }
             if let Some(PacRet { leaf, pc, key }) = pac_ret {
                 if pc {
                     to_add.push(llvm::CreateAttrString(cx.llcx, "branch-protection-pauth-lr"));
@@ -435,14 +450,15 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
     {
         to_add.push(create_alloc_family_attr(cx.llcx));
-        if let Some(zv) =
-            cx.tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant)
+        if let Some(instance) = instance
+            && let Some(zv) =
+                tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant)
             && let Some(name) = zv.value_str()
         {
             to_add.push(llvm::CreateAttrStringValue(
                 cx.llcx,
                 "alloc-variant-zeroed",
-                &mangle_internal_symbol(cx.tcx, name.as_str()),
+                &mangle_internal_symbol(tcx, name.as_str()),
             ));
         }
         // apply to argument place instead of function
@@ -487,18 +503,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     if let Some(align) = codegen_fn_attrs.alignment {
         llvm::set_alignment(llfn, align);
     }
-    if let Some(backchain) = backchain_attr(cx) {
+    if let Some(backchain) = backchain_attr(cx, sess) {
         to_add.push(backchain);
     }
-    to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry));
+    to_add.extend(patchable_function_entry_attrs(
+        cx,
+        sess,
+        codegen_fn_attrs.patchable_function_entry,
+    ));
 
     // Always annotate functions with the target-cpu they are compiled for.
     // Without this, ThinLTO won't inline Rust functions into Clang generated
     // functions (because Clang annotates functions this way too).
-    to_add.push(target_cpu_attr(cx));
+    to_add.push(target_cpu_attr(cx, sess));
     // tune-cpu is only conveyed through the attribute for our purpose.
     // The target doesn't care; the subtarget reads our attribute.
-    to_add.extend(tune_cpu_attr(cx));
+    to_add.extend(tune_cpu_attr(cx, sess));
 
     let function_features =
         codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
@@ -506,7 +526,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     // Apply function attributes as per usual if there are no user defined
     // target features otherwise this will get applied at the callsite.
     if function_features.is_empty() {
-        if let Some(inline_attr) = inline_attr(cx, instance) {
+        if let Some(instance) = instance
+            && let Some(inline_attr) = inline_attr(cx, tcx, instance)
+        {
             to_add.push(inline_attr);
         }
     }
@@ -514,7 +536,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
     let function_features = function_features
         .iter()
         // Convert to LLVMFeatures and filter out unavailable ones
-        .flat_map(|feat| llvm_util::to_llvm_features(cx.tcx.sess, feat))
+        .flat_map(|feat| llvm_util::to_llvm_features(sess, feat))
         // Convert LLVMFeatures & dependencies to +<feats>s
         .flat_map(|feat| feat.into_iter().map(|f| format!("+{f}")))
         .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
@@ -523,20 +545,22 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
         }))
         .collect::<Vec<String>>();
 
-    if cx.tcx.sess.target.is_like_wasm {
+    if sess.target.is_like_wasm {
         // If this function is an import from the environment but the wasm
         // import has a specific module/name, apply them here.
-        if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
+        if let Some(instance) = instance
+            && let Some(module) = wasm_import_module(tcx, instance.def_id())
+        {
             to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module));
 
             let name =
-                codegen_fn_attrs.symbol_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id()));
+                codegen_fn_attrs.symbol_name.unwrap_or_else(|| tcx.item_name(instance.def_id()));
             let name = name.as_str();
             to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
         }
     }
 
-    to_add.extend(target_features_attr(cx, function_features));
+    to_add.extend(target_features_attr(cx, tcx, function_features));
 
     attributes::apply_to_llfn(llfn, Function, &to_add);
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
index d5228f0e0de..903a882916e 100644
--- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -95,8 +95,6 @@ impl Drop for OwnedTargetMachine {
         // SAFETY: constructing ensures we have a valid pointer created by
         // llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no
         // double free or use after free.
-        unsafe {
-            llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr());
-        }
+        unsafe { llvm::LLVMDisposeTargetMachine(self.tm_unique) };
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index c4881f0aafc..1950b8288d1 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -204,6 +204,9 @@ pub(crate) fn target_machine_factory(
     optlvl: config::OptLevel,
     target_features: &[String],
 ) -> TargetMachineFactoryFn<LlvmCodegenBackend> {
+    // Self-profile timer for creating a _factory_.
+    let _prof_timer = sess.prof.generic_activity("target_machine_factory");
+
     let reloc_model = to_llvm_relocation_model(sess.relocation_model());
 
     let (opt_level, _) = to_llvm_opt_settings(optlvl);
@@ -259,6 +262,9 @@ pub(crate) fn target_machine_factory(
         .into_string()
         .unwrap_or_default();
     let command_line_args = quote_command_line_args(&sess.expanded_args);
+    // Self-profile counter for the number of bytes produced by command-line quoting.
+    // Values are summed, so the summary result is cumulative across all TM factories.
+    sess.prof.artifact_size("quoted_command_line_args", "-", command_line_args.len() as u64);
 
     let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
     match sess.opts.debuginfo_compression {
@@ -281,7 +287,11 @@ pub(crate) fn target_machine_factory(
 
     let use_wasm_eh = wants_wasm_eh(sess);
 
+    let prof = SelfProfilerRef::clone(&sess.prof);
     Arc::new(move |config: TargetMachineFactoryConfig| {
+        // Self-profile timer for invoking a factory to create a target machine.
+        let _prof_timer = prof.generic_activity("target_machine_factory_inner");
+
         let path_to_cstring_helper = |path: Option<PathBuf>| -> CString {
             let path = path.unwrap_or_default();
             let path = path_mapping
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 978134cc32b..6d12b511e9c 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -105,7 +105,7 @@ pub(crate) fn compile_codegen_unit(
             if let Some(entry) =
                 maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit)
             {
-                let attrs = attributes::sanitize_attrs(&cx, SanitizerSet::empty());
+                let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerSet::empty());
                 attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
             }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 0f17cc9063a..a4dc4eb532f 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1433,7 +1433,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 // If there is an inline attribute and a target feature that matches
                 // we will add the attribute to the callsite otherwise we'll omit
                 // this and not add the attribute to prevent soundness issues.
-                && let Some(inlining_rule) = attributes::inline_attr(&self.cx, instance)
+                && let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, instance)
                 && self.cx.tcx.is_target_feature_call_safe(
                     &fn_call_attrs.target_features,
                     &fn_defn_attrs.target_features,
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 4a8ea11a3a8..aa5c17269fb 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -370,7 +370,8 @@ pub(crate) unsafe fn create_module<'ll>(
         );
     }
 
-    if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
+    if let Some(BranchProtection { bti, pac_ret, gcs }) = sess.opts.unstable_opts.branch_protection
+    {
         if sess.target.arch == "aarch64" {
             llvm::add_module_flag_u32(
                 llmod,
@@ -403,6 +404,12 @@ pub(crate) unsafe fn create_module<'ll>(
                 "sign-return-address-with-bkey",
                 u32::from(pac_opts.key == PAuthKey::B),
             );
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Min,
+                "guarded-control-stack",
+                gcs.into(),
+            );
         } else {
             bug!(
                 "branch-protection used on non-AArch64 target; \
@@ -869,7 +876,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 } else {
                     let fty = self.type_variadic_func(&[], self.type_i32());
                     let llfn = self.declare_cfn(name, llvm::UnnamedAddr::Global, fty);
-                    let target_cpu = attributes::target_cpu_attr(self);
+                    let target_cpu = attributes::target_cpu_attr(self, self.sess());
                     attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[target_cpu]);
                     llfn
                 }
@@ -884,15 +891,15 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     fn set_frame_pointer_type(&self, llfn: &'ll Value) {
-        if let Some(attr) = attributes::frame_pointer_type_attr(self) {
+        if let Some(attr) = attributes::frame_pointer_type_attr(self, self.sess()) {
             attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[attr]);
         }
     }
 
     fn apply_target_cpu_attr(&self, llfn: &'ll Value) {
         let mut attrs = SmallVec::<[_; 2]>::new();
-        attrs.push(attributes::target_cpu_attr(self));
-        attrs.extend(attributes::tune_cpu_attr(self));
+        attrs.push(attributes::target_cpu_attr(self, self.sess()));
+        attrs.extend(attributes::tune_cpu_attr(self, self.sess()));
         attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs);
     }
 
@@ -911,7 +918,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             attributes::apply_to_llfn(
                 llfn,
                 llvm::AttributePlace::Function,
-                attributes::target_features_attr(self, vec![]).as_slice(),
+                attributes::target_features_attr(self, self.tcx, vec![]).as_slice(),
             );
             Some(llfn)
         } else {
@@ -1037,7 +1044,10 @@ impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> {
 impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
-        if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
+        if let LayoutError::SizeOverflow(_)
+        | LayoutError::ReferencesError(_)
+        | LayoutError::InvalidSimd { .. } = err
+        {
             self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() })
         } else {
             self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
@@ -1054,7 +1064,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         match err {
-            FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => {
+            FnAbiError::Layout(
+                LayoutError::SizeOverflow(_)
+                | LayoutError::Cycle(_)
+                | LayoutError::InvalidSimd { .. },
+            ) => {
                 self.tcx.dcx().emit_fatal(Spanned { span, node: err });
             }
             _ => match fn_abi_request {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 7a6dc008c7b..3081badb821 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -2,9 +2,9 @@
 
 use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
 use rustc_codegen_ssa::traits::*;
+use rustc_hir::attrs::DebuggerVisualizerType;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
-use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
 use rustc_session::config::{CrateType, DebugInfo};
 
 use crate::builder::Builder;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index aa8b8bd152d..4ba72cd61a0 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -477,8 +477,8 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
         ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id),
         ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id),
         ty::Adt(def, ..) => match def.adt_kind() {
-            AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id),
-            AdtKind::Union => build_union_type_di_node(cx, unique_type_id),
+            AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id, span),
+            AdtKind::Union => build_union_type_di_node(cx, unique_type_id, span),
             AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span),
         },
         ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
@@ -1076,6 +1076,7 @@ fn visibility_di_flags<'ll, 'tcx>(
 fn build_struct_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     unique_type_id: UniqueTypeId<'tcx>,
+    span: Span,
 ) -> DINodeCreationResult<'ll> {
     let struct_type = unique_type_id.expect_ty();
     let ty::Adt(adt_def, _) = struct_type.kind() else {
@@ -1083,7 +1084,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
     };
     assert!(adt_def.is_struct());
     let containing_scope = get_namespace_for_item(cx, adt_def.did());
-    let struct_type_and_layout = cx.layout_of(struct_type);
+    let struct_type_and_layout = cx.spanned_layout_of(struct_type, span);
     let variant_def = adt_def.non_enum_variant();
     let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
         Some(file_metadata_from_def_id(cx, Some(adt_def.did())))
@@ -1276,6 +1277,7 @@ fn build_closure_env_di_node<'ll, 'tcx>(
 fn build_union_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     unique_type_id: UniqueTypeId<'tcx>,
+    span: Span,
 ) -> DINodeCreationResult<'ll> {
     let union_type = unique_type_id.expect_ty();
     let (union_def_id, variant_def) = match union_type.kind() {
@@ -1283,7 +1285,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
         _ => bug!("build_union_type_di_node on a non-ADT"),
     };
     let containing_scope = get_namespace_for_item(cx, union_def_id);
-    let union_ty_and_layout = cx.layout_of(union_type);
+    let union_ty_and_layout = cx.spanned_layout_of(union_type, span);
     let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
     let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
         Some(file_metadata_from_def_id(cx, Some(union_def_id)))
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 960a895a203..36cdb498839 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -76,7 +76,7 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>(
         attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx));
     }
 
-    attrs.extend(attributes::non_lazy_bind_attr(cx));
+    attrs.extend(attributes::non_lazy_bind_attr(cx, cx.tcx.sess));
 
     attributes::apply_to_llfn(llfn, Function, &attrs);
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e7f4a357048..50398a32142 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -18,7 +18,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, Symbol, sym};
 use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
 use rustc_target::callconv::PassMode;
-use rustc_target::spec::PanicStrategy;
 use tracing::debug;
 
 use crate::abi::FnAbiLlvmExt;
@@ -674,7 +673,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>(
     catch_func: &'ll Value,
     dest: PlaceRef<'tcx, &'ll Value>,
 ) {
-    if bx.sess().panic_strategy() == PanicStrategy::Abort {
+    if !bx.sess().panic_strategy().unwinds() {
         let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
         bx.call(try_func_ty, None, None, try_func, &[data], None, None);
         // Return 0 unconditionally from the intrinsic call;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 9a86e4373d8..38a6a311954 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -710,6 +710,7 @@ pub(crate) enum MemoryEffects {
     None,
     ReadOnly,
     InaccessibleMemOnly,
+    ReadOnlyNotPure,
 }
 
 /// LLVMOpcode
@@ -1052,6 +1053,8 @@ unsafe extern "C" {
         SLen: c_uint,
     ) -> MetadataKindId;
 
+    pub(crate) fn LLVMDisposeTargetMachine(T: ptr::NonNull<TargetMachine>);
+
     // Create modules.
     pub(crate) fn LLVMModuleCreateWithNameInContext(
         ModuleID: *const c_char,
@@ -2498,7 +2501,6 @@ unsafe extern "C" {
         UseWasmEH: bool,
     ) -> *mut TargetMachine;
 
-    pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
     pub(crate) fn LLVMRustAddLibraryInfo<'a>(
         PM: &PassManager<'a>,
         M: &'a Module,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 45c5c9aa551..3b920168e06 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -106,7 +106,7 @@ unsafe fn configure_llvm(sess: &Session) {
 
         if sess.target.os == "emscripten"
             && !sess.opts.unstable_opts.emscripten_wasm_eh
-            && sess.panic_strategy() == PanicStrategy::Unwind
+            && sess.panic_strategy().unwinds()
         {
             add("-enable-emscripten-cxx-exceptions", false);
         }
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 5462163f4ff..9c5a3d839ce 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -8,9 +8,7 @@ edition = "2024"
 ar_archive_writer = "0.5"
 bitflags = "2.4.1"
 bstr = "1.11.3"
-# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
-# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_windows_rc`.
-cc = "=1.2.16"
+find-msvc-tools = "0.1.2"
 itertools = "0.12"
 pathdiff = "0.2.0"
 regex = "1.4"
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 48b01ea2df1..d6c304c1b14 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -9,7 +9,7 @@ use std::path::{Path, PathBuf};
 use std::process::{Output, Stdio};
 use std::{env, fmt, fs, io, mem, str};
 
-use cc::windows_registry;
+use find_msvc_tools;
 use itertools::Itertools;
 use regex::Regex;
 use rustc_arena::TypedArena;
@@ -47,8 +47,8 @@ use rustc_span::Symbol;
 use rustc_target::spec::crt_objects::CrtObjects;
 use rustc_target::spec::{
     BinaryFormat, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault,
-    LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel,
-    SanitizerSet, SplitDebuginfo,
+    LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, RelocModel, RelroLevel, SanitizerSet,
+    SplitDebuginfo,
 };
 use tracing::{debug, info, warn};
 
@@ -877,9 +877,9 @@ fn link_natively(
                     // All Microsoft `link.exe` linking ror codes are
                     // four digit numbers in the range 1000 to 9999 inclusive
                     if is_msvc_link_exe && (code < 1000 || code > 9999) {
-                        let is_vs_installed = windows_registry::find_vs_version().is_ok();
+                        let is_vs_installed = find_msvc_tools::find_vs_version().is_ok();
                         let has_linker =
-                            windows_registry::find_tool(&sess.target.arch, "link.exe").is_some();
+                            find_msvc_tools::find_tool(&sess.target.arch, "link.exe").is_some();
 
                         sess.dcx().emit_note(errors::LinkExeUnexpectedError);
 
@@ -2512,10 +2512,10 @@ fn add_order_independent_options(
     if sess.target.os == "emscripten" {
         cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh {
             "-fwasm-exceptions"
-        } else if sess.panic_strategy() == PanicStrategy::Abort {
-            "-sDISABLE_EXCEPTION_CATCHING=1"
-        } else {
+        } else if sess.panic_strategy().unwinds() {
             "-sDISABLE_EXCEPTION_CATCHING=0"
+        } else {
+            "-sDISABLE_EXCEPTION_CATCHING=1"
         });
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index a2efd420a32..624ab1b5084 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -4,7 +4,7 @@ use std::io::prelude::*;
 use std::path::{Path, PathBuf};
 use std::{env, io, iter, mem, str};
 
-use cc::windows_registry;
+use find_msvc_tools;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::{
     find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
@@ -53,7 +53,7 @@ pub(crate) fn get_linker<'a>(
     self_contained: bool,
     target_cpu: &'a str,
 ) -> Box<dyn Linker + 'a> {
-    let msvc_tool = windows_registry::find_tool(&sess.target.arch, "link.exe");
+    let msvc_tool = find_msvc_tools::find_tool(&sess.target.arch, "link.exe");
 
     // If our linker looks like a batch script on Windows then to execute this
     // we'll need to spawn `cmd` explicitly. This is primarily done to handle
@@ -117,7 +117,6 @@ pub(crate) fn get_linker<'a>(
     if sess.target.is_like_msvc
         && let Some(ref tool) = msvc_tool
     {
-        cmd.args(tool.args());
         for (k, v) in tool.env() {
             if k == "PATH" {
                 new_path.extend(env::split_paths(v));
@@ -845,6 +844,11 @@ impl<'a> Linker for GccLinker<'a> {
                 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
             }
             self.link_arg("--dynamic-list").link_arg(path);
+        } else if self.sess.target.is_like_wasm {
+            self.link_arg("--no-export-dynamic");
+            for (sym, _) in symbols {
+                self.link_arg("--export").link_arg(sym);
+            }
         } else {
             // Write an LD version script
             let res: io::Result<()> = try {
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 68a2f43ec67..422b06350e1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -11,12 +11,12 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
 use rustc_data_structures::unord::UnordMap;
-use rustc_hir::attrs::OptimizeAttr;
+use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemId, Target};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
 use rustc_middle::middle::lang_items;
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 700d7c26752..010ffa60c7a 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -476,14 +476,20 @@ const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wid
 const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value
 const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
 const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
-const_eval_validation_null_box = {$front_matter}: encountered a null box
+const_eval_validation_null_box = {$front_matter}: encountered a {$maybe ->
+    [true] maybe-null
+    *[false] null
+  } box
 const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer
-const_eval_validation_null_ref = {$front_matter}: encountered a null reference
-const_eval_validation_nullable_ptr_out_of_range = {$front_matter}: encountered a potentially null pointer, but expected something that cannot possibly fail to be {$in_range}
+const_eval_validation_null_ref = {$front_matter}: encountered a {$maybe ->
+    [true] maybe-null
+    *[false] null
+  } reference
+const_eval_validation_nonnull_ptr_out_of_range = {$front_matter}: encountered a maybe-null pointer, but expected something that is definitely non-zero
 const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but expected something {$in_range}
 const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers
 const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected}
-const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range}
+const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer with unknown absolute address, but expected something that is definitely {$in_range}
 const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty}
 const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes})
 const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes})
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 2d412ee5ec2..d352a638424 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -668,7 +668,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             MutableRefInConst => const_eval_validation_mutable_ref_in_const,
             NullFnPtr => const_eval_validation_null_fn_ptr,
             NeverVal => const_eval_validation_never_val,
-            NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
+            NonnullPtrMaybeNull { .. } => const_eval_validation_nonnull_ptr_out_of_range,
             PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
             OutOfRange { .. } => const_eval_validation_out_of_range,
             UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
@@ -696,8 +696,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             }
             UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
 
-            NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
-            NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
+            NullPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_null_box,
+            NullPtr { ptr_kind: PointerKind::Ref(_), .. } => const_eval_validation_null_ref,
             DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
                 const_eval_validation_dangling_box_no_provenance
             }
@@ -804,9 +804,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
             | InvalidFnPtr { value } => {
                 err.arg("value", value);
             }
-            NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
-                add_range_arg(range, max_value, err)
-            }
+            PtrOutOfRange { range, max_value } => add_range_arg(range, max_value, err),
             OutOfRange { range, max_value, value } => {
                 err.arg("value", value);
                 add_range_arg(range, max_value, err);
@@ -822,10 +820,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                 err.arg("vtable_dyn_type", vtable_dyn_type.to_string());
                 err.arg("expected_dyn_type", expected_dyn_type.to_string());
             }
-            NullPtr { .. }
-            | MutableRefToImmutable
+            NullPtr { maybe, .. } => {
+                err.arg("maybe", maybe);
+            }
+            MutableRefToImmutable
             | MutableRefInConst
             | NullFnPtr
+            | NonnullPtrMaybeNull
             | NeverVal
             | UnsafeCellInImmutable
             | InvalidMetaSliceTooLarge { .. }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 418dd658121..785978b4d71 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -636,6 +636,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 dest,
                 rustc_apfloat::Round::NearestTiesToEven,
             )?,
+            sym::fmaf16 => self.fma_intrinsic::<Half>(args, dest)?,
+            sym::fmaf32 => self.fma_intrinsic::<Single>(args, dest)?,
+            sym::fmaf64 => self.fma_intrinsic::<Double>(args, dest)?,
+            sym::fmaf128 => self.fma_intrinsic::<Quad>(args, dest)?,
+            sym::fmuladdf16 => self.float_muladd_intrinsic::<Half>(args, dest)?,
+            sym::fmuladdf32 => self.float_muladd_intrinsic::<Single>(args, dest)?,
+            sym::fmuladdf64 => self.float_muladd_intrinsic::<Double>(args, dest)?,
+            sym::fmuladdf128 => self.float_muladd_intrinsic::<Quad>(args, dest)?,
 
             // Unsupported intrinsic: skip the return_to_block below.
             _ => return interp_ok(false),
@@ -1035,4 +1043,42 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         self.write_scalar(res, dest)?;
         interp_ok(())
     }
+
+    fn fma_intrinsic<F>(
+        &mut self,
+        args: &[OpTy<'tcx, M::Provenance>],
+        dest: &PlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ()>
+    where
+        F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
+    {
+        let a: F = self.read_scalar(&args[0])?.to_float()?;
+        let b: F = self.read_scalar(&args[1])?.to_float()?;
+        let c: F = self.read_scalar(&args[2])?.to_float()?;
+
+        let res = a.mul_add(b, c).value;
+        let res = self.adjust_nan(res, &[a, b, c]);
+        self.write_scalar(res, dest)?;
+        interp_ok(())
+    }
+
+    fn float_muladd_intrinsic<F>(
+        &mut self,
+        args: &[OpTy<'tcx, M::Provenance>],
+        dest: &PlaceTy<'tcx, M::Provenance>,
+    ) -> InterpResult<'tcx, ()>
+    where
+        F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
+    {
+        let a: F = self.read_scalar(&args[0])?.to_float()?;
+        let b: F = self.read_scalar(&args[1])?.to_float()?;
+        let c: F = self.read_scalar(&args[2])?.to_float()?;
+
+        let fuse = M::float_fuse_mul_add(self);
+
+        let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value };
+        let res = self.adjust_nan(res, &[a, b, c]);
+        self.write_scalar(res, dest)?;
+        interp_ok(())
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index e22629993fb..1725635e0b4 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -289,6 +289,9 @@ pub trait Machine<'tcx>: Sized {
         a
     }
 
+    /// Determines whether the `fmuladd` intrinsics fuse the multiply-add or use separate operations.
+    fn float_fuse_mul_add(_ecx: &mut InterpCx<'tcx, Self>) -> bool;
+
     /// Called before a basic block terminator is executed.
     #[inline]
     fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
@@ -673,6 +676,11 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
     }
 
     #[inline(always)]
+    fn float_fuse_mul_add(_ecx: &mut InterpCx<$tcx, Self>) -> bool {
+        true
+    }
+
+    #[inline(always)]
     fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> {
         // We can't look at `tcx.sess` here as that can differ across crates, which can lead to
         // unsound differences in evaluating the same constant at different instantiation sites.
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 9adc3fa4631..5f088fe37e8 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -511,7 +511,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
             ),
             self.path,
-            Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind },
+            Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
             Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
                 ptr_kind,
                 // FIXME this says "null pointer" when null but we need translate
@@ -538,8 +538,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         );
         // Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
         // that does not imply non-null.
-        if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? {
-            throw_validation_failure!(self.path, NullPtr { ptr_kind })
+        let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx);
+        if self.ecx.scalar_may_be_null(scalar)? {
+            let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
+            throw_validation_failure!(self.path, NullPtr { ptr_kind, maybe })
         }
         // Do not allow references to uninhabited types.
         if place.layout.is_uninhabited() {
@@ -757,6 +759,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 } else {
                     // Otherwise (for standalone Miri), we have to still check it to be non-null.
                     if self.ecx.scalar_may_be_null(scalar)? {
+                        let maybe =
+                            !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
+                        // This can't be a "maybe-null" pointer since the check for this being
+                        // a fn ptr at all already ensures that the pointer is inbounds.
+                        assert!(!maybe);
                         throw_validation_failure!(self.path, NullFnPtr);
                     }
                 }
@@ -819,10 +826,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 if start == 1 && end == max_value {
                     // Only null is the niche. So make sure the ptr is NOT null.
                     if self.ecx.scalar_may_be_null(scalar)? {
-                        throw_validation_failure!(
-                            self.path,
-                            NullablePtrOutOfRange { range: valid_range, max_value }
-                        )
+                        throw_validation_failure!(self.path, NonnullPtrMaybeNull)
                     } else {
                         return interp_ok(());
                     }
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 5249b32eca4..4e7c8310007 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -61,7 +61,7 @@ pub(crate) fn const_caller_location_provider(
     trace!("const_caller_location: {}:{}:{}", file, line, col);
     let mut ecx = mk_eval_cx_to_read_const_val(
         tcx,
-        rustc_span::DUMMY_SP, // FIXME: use a proper span here?
+        rustc_span::DUMMY_SP, // This interpreter cannot fail, so the span is irrelevant.
         ty::TypingEnv::fully_monomorphized(),
         CanAccessMutGlobal::No,
     );
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 7db1be24f24..33b712e3aed 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -942,9 +942,9 @@ impl SyntaxExtension {
                 .unwrap_or_default();
         let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe(_));
 
-        let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export)
-            .and_then(|macro_export| macro_export.meta_item_list())
-            .is_some_and(|l| ast::attr::list_contains_name(&l, sym::local_inner_macros));
+        let local_inner_macros =
+            *find_attr!(attrs, AttributeKind::MacroExport {local_inner_macros: l, ..} => l)
+                .unwrap_or(&false);
         let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local);
         tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
 
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index d2b275ad20a..70d796cda11 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, PResult};
 use rustc_macros::{Decodable, Encodable};
 use rustc_session::parse::ParseSess;
-use rustc_span::{Ident, Span, Symbol};
+use rustc_span::{Ident, Span, Symbol, sym};
 
 use crate::errors;
 
@@ -69,15 +69,15 @@ impl MetaVarExpr {
         }
 
         let mut iter = args.iter();
-        let rslt = match ident.as_str() {
-            "concat" => parse_concat(&mut iter, psess, outer_span, ident.span)?,
-            "count" => parse_count(&mut iter, psess, ident.span)?,
-            "ignore" => {
+        let rslt = match ident.name {
+            sym::concat => parse_concat(&mut iter, psess, outer_span, ident.span)?,
+            sym::count => parse_count(&mut iter, psess, ident.span)?,
+            sym::ignore => {
                 eat_dollar(&mut iter, psess, ident.span)?;
                 MetaVarExpr::Ignore(parse_ident(&mut iter, psess, ident.span)?)
             }
-            "index" => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?),
-            "len" => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?),
+            sym::index => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?),
+            sym::len => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?),
             _ => {
                 let err = errors::MveUnrecognizedExpr {
                     span: ident.span,
@@ -119,14 +119,13 @@ fn check_trailing_tokens<'psess>(
     }
 
     // `None` for max indicates the arg count must be exact, `Some` indicates a range is accepted.
-    let (min_or_exact_args, max_args) = match ident.as_str() {
-        "concat" => panic!("concat takes unlimited tokens but didn't eat them all"),
-        "ignore" => (1, None),
+    let (min_or_exact_args, max_args) = match ident.name {
+        sym::concat => panic!("concat takes unlimited tokens but didn't eat them all"),
+        sym::ignore => (1, None),
         // 1 or 2 args
-        "count" => (1, Some(2)),
+        sym::count => (1, Some(2)),
         // 0 or 1 arg
-        "index" => (0, Some(1)),
-        "len" => (0, Some(1)),
+        sym::index | sym::len => (0, Some(1)),
         other => unreachable!("unknown MVEs should be rejected earlier (got `{other}`)"),
     };
 
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 6a3f1f62c91..dddd62a4945 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -375,6 +375,19 @@ fn transcribe_metavar<'tx>(
         return Ok(());
     };
 
+    let MatchedSingle(pnr) = cur_matched else {
+        // We were unable to descend far enough. This is an error.
+        return Err(dcx.create_err(MacroVarStillRepeating { span: sp, ident }));
+    };
+
+    transcribe_pnr(tscx, sp, pnr)
+}
+
+fn transcribe_pnr<'tx>(
+    tscx: &mut TranscrCtx<'tx, '_>,
+    mut sp: Span,
+    pnr: &ParseNtResult,
+) -> PResult<'tx, ()> {
     // We wrap the tokens in invisible delimiters, unless they are already wrapped
     // in invisible delimiters with the same `MetaVarKind`. Because some proc
     // macros can't handle multiple layers of invisible delimiters of the same
@@ -404,33 +417,33 @@ fn transcribe_metavar<'tx>(
         )
     };
 
-    let tt = match cur_matched {
-        MatchedSingle(ParseNtResult::Tt(tt)) => {
+    let tt = match pnr {
+        ParseNtResult::Tt(tt) => {
             // `tt`s are emitted into the output stream directly as "raw tokens",
             // without wrapping them into groups. Other variables are emitted into
             // the output stream as groups with `Delimiter::Invisible` to maintain
             // parsing priorities.
             maybe_use_metavar_location(tscx.psess, &tscx.stack, sp, tt, &mut tscx.marker)
         }
-        MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
+        ParseNtResult::Ident(ident, is_raw) => {
             tscx.marker.mark_span(&mut sp);
             with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
             let kind = token::NtIdent(*ident, *is_raw);
             TokenTree::token_alone(kind, sp)
         }
-        MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => {
+        ParseNtResult::Lifetime(ident, is_raw) => {
             tscx.marker.mark_span(&mut sp);
             with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
             let kind = token::NtLifetime(*ident, *is_raw);
             TokenTree::token_alone(kind, sp)
         }
-        MatchedSingle(ParseNtResult::Item(item)) => {
+        ParseNtResult::Item(item) => {
             mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item))
         }
-        MatchedSingle(ParseNtResult::Block(block)) => {
+        ParseNtResult::Block(block) => {
             mk_delimited(block.span, MetaVarKind::Block, TokenStream::from_ast(block))
         }
-        MatchedSingle(ParseNtResult::Stmt(stmt)) => {
+        ParseNtResult::Stmt(stmt) => {
             let stream = if let StmtKind::Empty = stmt.kind {
                 // FIXME: Properly collect tokens for empty statements.
                 TokenStream::token_alone(token::Semi, stmt.span)
@@ -439,10 +452,10 @@ fn transcribe_metavar<'tx>(
             };
             mk_delimited(stmt.span, MetaVarKind::Stmt, stream)
         }
-        MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => {
+        ParseNtResult::Pat(pat, pat_kind) => {
             mk_delimited(pat.span, MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat))
         }
-        MatchedSingle(ParseNtResult::Expr(expr, kind)) => {
+        ParseNtResult::Expr(expr, kind) => {
             let (can_begin_literal_maybe_minus, can_begin_string_literal) = match &expr.kind {
                 ExprKind::Lit(_) => (true, true),
                 ExprKind::Unary(UnOp::Neg, e) if matches!(&e.kind, ExprKind::Lit(_)) => {
@@ -460,14 +473,14 @@ fn transcribe_metavar<'tx>(
                 TokenStream::from_ast(expr),
             )
         }
-        MatchedSingle(ParseNtResult::Literal(lit)) => {
+        ParseNtResult::Literal(lit) => {
             mk_delimited(lit.span, MetaVarKind::Literal, TokenStream::from_ast(lit))
         }
-        MatchedSingle(ParseNtResult::Ty(ty)) => {
+        ParseNtResult::Ty(ty) => {
             let is_path = matches!(&ty.kind, TyKind::Path(None, _path));
             mk_delimited(ty.span, MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty))
         }
-        MatchedSingle(ParseNtResult::Meta(attr_item)) => {
+        ParseNtResult::Meta(attr_item) => {
             let has_meta_form = attr_item.meta_kind().is_some();
             mk_delimited(
                 attr_item.span(),
@@ -475,16 +488,12 @@ fn transcribe_metavar<'tx>(
                 TokenStream::from_ast(attr_item),
             )
         }
-        MatchedSingle(ParseNtResult::Path(path)) => {
+        ParseNtResult::Path(path) => {
             mk_delimited(path.span, MetaVarKind::Path, TokenStream::from_ast(path))
         }
-        MatchedSingle(ParseNtResult::Vis(vis)) => {
+        ParseNtResult::Vis(vis) => {
             mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
         }
-        MatchedSeq(..) => {
-            // We were unable to descend far enough. This is an error.
-            return Err(dcx.create_err(MacroVarStillRepeating { span: sp, ident }));
-        }
     };
 
     tscx.result.push(tt);
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 99d6e93faa9..220388ffe43 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1212,6 +1212,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         niche optimizations in the standard library",
     ),
     rustc_attr!(
+        rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing,
+        EncodeCrossCrate::Yes,
+        "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
+        for better error messages",
+    ),
+    rustc_attr!(
         rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::Yes,
         "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 0784675b177..ddcbaeaad88 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -363,6 +363,20 @@ pub struct LinkEntry {
     pub import_name_type: Option<(PeImportNameType, Span)>,
 }
 
+#[derive(HashStable_Generic, PrintAttribute)]
+#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+pub enum DebuggerVisualizerType {
+    Natvis,
+    GdbPrettyPrinter,
+}
+
+#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
+pub struct DebugVisualizer {
+    pub span: Span,
+    pub visualizer_type: DebuggerVisualizerType,
+    pub path: Symbol,
+}
+
 /// Represents parsed *built-in* inert attributes.
 ///
 /// ## Overview
@@ -485,7 +499,10 @@ pub enum AttributeKind {
     /// Represents `#[custom_mir]`.
     CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
 
-    ///Represents `#[rustc_deny_explicit_impl]`.
+    /// Represents `#[debugger_visualizer]`.
+    DebuggerVisualizer(ThinVec<DebugVisualizer>),
+
+    /// Represents `#[rustc_deny_explicit_impl]`.
     DenyExplicitImpl(Span),
 
     /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
@@ -551,6 +568,9 @@ pub enum AttributeKind {
     /// Represents `#[macro_escape]`.
     MacroEscape(Span),
 
+    /// Represents [`#[macro_export]`](https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.scope.path).
+    MacroExport { span: Span, local_inner_macros: bool },
+
     /// Represents `#[rustc_macro_transparency]`.
     MacroTransparency(Transparency),
 
@@ -648,6 +668,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_object_lifetime_default]`.
     RustcObjectLifetimeDefault,
 
+    /// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
+    RustcSimdMonomorphizeLaneLimit(Limit),
+
     /// Represents `#[sanitize]`
     ///
     /// the on set and off set are distjoint since there's a third option: unset.
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index 563e7a58c6d..1611b865c77 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -37,6 +37,7 @@ impl AttributeKind {
             Coverage(..) => No,
             CrateName { .. } => No,
             CustomMir(_, _, _) => Yes,
+            DebuggerVisualizer(..) => No,
             DenyExplicitImpl(..) => No,
             Deprecation { .. } => Yes,
             DoNotImplementViaObject(..) => No,
@@ -56,6 +57,7 @@ impl AttributeKind {
             Linkage(..) => No,
             LoopMatch(..) => No,
             MacroEscape(..) => No,
+            MacroExport { .. } => Yes,
             MacroTransparency(..) => Yes,
             MacroUse { .. } => No,
             Marker(..) => No,
@@ -87,6 +89,7 @@ impl AttributeKind {
             RustcLayoutScalarValidRangeEnd(..) => Yes,
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcObjectLifetimeDefault => No,
+            RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
             Sanitize { .. } => No,
             ShouldPanic { .. } => No,
             SkipDuringMethodDispatch { .. } => No,
diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs
index 0b24052b453..b7a0a6a0c19 100644
--- a/compiler/rustc_hir/src/lints.rs
+++ b/compiler/rustc_hir/src/lints.rs
@@ -31,9 +31,34 @@ pub struct AttributeLint<Id> {
 
 #[derive(Clone, Debug, HashStable_Generic)]
 pub enum AttributeLintKind {
-    UnusedDuplicate { this: Span, other: Span, warning: bool },
-    IllFormedAttributeInput { suggestions: Vec<String> },
-    EmptyAttribute { first_span: Span },
-    InvalidTarget { name: AttrPath, target: Target, applied: Vec<String>, only: &'static str },
-    InvalidStyle { name: AttrPath, is_used_as_inner: bool, target: Target, target_span: Span },
+    UnusedDuplicate {
+        this: Span,
+        other: Span,
+        warning: bool,
+    },
+    IllFormedAttributeInput {
+        suggestions: Vec<String>,
+    },
+    EmptyAttribute {
+        first_span: Span,
+    },
+
+    /// Copy of `IllFormedAttributeInput`
+    /// specifically for the `invalid_macro_export_arguments` lint until that is removed,
+    /// see <https://github.com/rust-lang/rust/pull/143857#issuecomment-3079175663>
+    InvalidMacroExportArguments {
+        suggestions: Vec<String>,
+    },
+    InvalidTarget {
+        name: AttrPath,
+        target: Target,
+        applied: Vec<String>,
+        only: &'static str,
+    },
+    InvalidStyle {
+        name: AttrPath,
+        is_used_as_inner: bool,
+        target: Target,
+        target_span: Span,
+    },
 }
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index aa2d27ab809..bc3448be582 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -64,83 +64,159 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
         // it's usually worth updating that intrinsic's documentation
         // to note that it's safe to call, since
         // safe extern fns are otherwise unprecedented.
-        sym::abort
+
+        // tidy-alphabetical-start
+        | sym::abort
+        | sym::add_with_overflow
+        | sym::aggregate_raw_ptr
+        | sym::align_of
         | sym::assert_inhabited
-        | sym::assert_zero_valid
         | sym::assert_mem_uninitialized_valid
+        | sym::assert_zero_valid
+        | sym::autodiff
+        | sym::bitreverse
+        | sym::black_box
         | sym::box_new
         | sym::breakpoint
-        | sym::size_of
-        | sym::align_of
-        | sym::needs_drop
+        | sym::bswap
         | sym::caller_location
-        | sym::add_with_overflow
-        | sym::sub_with_overflow
-        | sym::mul_with_overflow
         | sym::carrying_mul_add
-        | sym::wrapping_add
-        | sym::wrapping_sub
-        | sym::wrapping_mul
-        | sym::saturating_add
-        | sym::saturating_sub
-        | sym::rotate_left
-        | sym::rotate_right
-        | sym::ctpop
+        | sym::ceilf16
+        | sym::ceilf32
+        | sym::ceilf64
+        | sym::ceilf128
+        | sym::cold_path
+        | sym::const_eval_select
+        | sym::contract_check_ensures
+        | sym::contract_check_requires
+        | sym::contract_checks
+        | sym::copysignf16
+        | sym::copysignf32
+        | sym::copysignf64
+        | sym::copysignf128
+        | sym::cosf16
+        | sym::cosf32
+        | sym::cosf64
+        | sym::cosf128
         | sym::ctlz
+        | sym::ctpop
         | sym::cttz
-        | sym::bswap
-        | sym::bitreverse
-        | sym::three_way_compare
         | sym::discriminant_value
-        | sym::type_id
-        | sym::type_id_eq
-        | sym::select_unpredictable
-        | sym::cold_path
-        | sym::ptr_guaranteed_cmp
-        | sym::minnumf16
-        | sym::minnumf32
-        | sym::minnumf64
-        | sym::minnumf128
-        | sym::minimumf16
-        | sym::minimumf32
-        | sym::minimumf64
-        | sym::minimumf128
-        | sym::maxnumf16
-        | sym::maxnumf32
-        | sym::maxnumf64
-        | sym::maxnumf128
+        | sym::exp2f16
+        | sym::exp2f32
+        | sym::exp2f64
+        | sym::exp2f128
+        | sym::expf16
+        | sym::expf32
+        | sym::expf64
+        | sym::expf128
+        | sym::fabsf16
+        | sym::fabsf32
+        | sym::fabsf64
+        | sym::fabsf128
+        | sym::fadd_algebraic
+        | sym::fdiv_algebraic
+        | sym::floorf16
+        | sym::floorf32
+        | sym::floorf64
+        | sym::floorf128
+        | sym::fmaf16
+        | sym::fmaf32
+        | sym::fmaf64
+        | sym::fmaf128
+        | sym::fmul_algebraic
+        | sym::fmuladdf16
+        | sym::fmuladdf32
+        | sym::fmuladdf64
+        | sym::fmuladdf128
+        | sym::forget
+        | sym::frem_algebraic
+        | sym::fsub_algebraic
+        | sym::is_val_statically_known
+        | sym::log2f16
+        | sym::log2f32
+        | sym::log2f64
+        | sym::log2f128
+        | sym::log10f16
+        | sym::log10f32
+        | sym::log10f64
+        | sym::log10f128
+        | sym::logf16
+        | sym::logf32
+        | sym::logf64
+        | sym::logf128
         | sym::maximumf16
         | sym::maximumf32
         | sym::maximumf64
         | sym::maximumf128
-        | sym::rustc_peek
-        | sym::type_name
-        | sym::forget
-        | sym::black_box
-        | sym::variant_count
-        | sym::is_val_statically_known
+        | sym::maxnumf16
+        | sym::maxnumf32
+        | sym::maxnumf64
+        | sym::maxnumf128
+        | sym::minimumf16
+        | sym::minimumf32
+        | sym::minimumf64
+        | sym::minimumf128
+        | sym::minnumf16
+        | sym::minnumf32
+        | sym::minnumf64
+        | sym::minnumf128
+        | sym::mul_with_overflow
+        | sym::needs_drop
+        | sym::powf16
+        | sym::powf32
+        | sym::powf64
+        | sym::powf128
+        | sym::powif16
+        | sym::powif32
+        | sym::powif64
+        | sym::powif128
+        | sym::prefetch_read_data
+        | sym::prefetch_read_instruction
+        | sym::prefetch_write_data
+        | sym::prefetch_write_instruction
+        | sym::ptr_guaranteed_cmp
         | sym::ptr_mask
-        | sym::aggregate_raw_ptr
         | sym::ptr_metadata
-        | sym::ub_checks
-        | sym::contract_checks
-        | sym::contract_check_requires
-        | sym::contract_check_ensures
-        | sym::fadd_algebraic
-        | sym::fsub_algebraic
-        | sym::fmul_algebraic
-        | sym::fdiv_algebraic
-        | sym::frem_algebraic
+        | sym::rotate_left
+        | sym::rotate_right
         | sym::round_ties_even_f16
         | sym::round_ties_even_f32
         | sym::round_ties_even_f64
         | sym::round_ties_even_f128
-        | sym::autodiff
-        | sym::prefetch_read_data
-        | sym::prefetch_write_data
-        | sym::prefetch_read_instruction
-        | sym::prefetch_write_instruction
-        | sym::const_eval_select => hir::Safety::Safe,
+        | sym::roundf16
+        | sym::roundf32
+        | sym::roundf64
+        | sym::roundf128
+        | sym::rustc_peek
+        | sym::saturating_add
+        | sym::saturating_sub
+        | sym::select_unpredictable
+        | sym::sinf16
+        | sym::sinf32
+        | sym::sinf64
+        | sym::sinf128
+        | sym::size_of
+        | sym::sqrtf16
+        | sym::sqrtf32
+        | sym::sqrtf64
+        | sym::sqrtf128
+        | sym::sub_with_overflow
+        | sym::three_way_compare
+        | sym::truncf16
+        | sym::truncf32
+        | sym::truncf64
+        | sym::truncf128
+        | sym::type_id
+        | sym::type_id_eq
+        | sym::type_name
+        | sym::ub_checks
+        | sym::variant_count
+        | sym::wrapping_add
+        | sym::wrapping_mul
+        | sym::wrapping_sub
+        // tidy-alphabetical-end
+        => hir::Safety::Safe,
         _ => hir::Safety::Unsafe,
     };
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index 7867c1c3b48..81deb35920a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -219,6 +219,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
         }
         Unknown(..)
         | SizeOverflow(..)
+        | InvalidSimd { .. }
         | NormalizationFailure(..)
         | ReferencesError(..)
         | Cycle(..) => {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index f735c0a4160..46accb76a18 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -47,7 +47,7 @@ You can read more about trait objects in the Trait Objects section of the Refere
 https://doc.rust-lang.org/reference/types.html#trait-objects";
 
 fn is_number(text: &str) -> bool {
-    text.chars().all(|c: char| c.is_digit(10))
+    text.chars().all(|c: char| c.is_ascii_digit())
 }
 
 /// Information about the expected type at the top level of type checking a pattern.
@@ -262,8 +262,9 @@ enum InheritedRefMatchRule {
         /// pattern matches a given type:
         /// - If the underlying type is not a reference, a reference pattern may eat the inherited reference;
         /// - If the underlying type is a reference, a reference pattern matches if it can eat either one
-        ///    of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the
-        ///    underlying type is `&mut` or the inherited reference is `&mut`.
+        ///   of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the
+        ///   underlying type is `&mut` or the inherited reference is `&mut`.
+        ///
         /// If `false`, a reference pattern is only matched against the underlying type.
         /// This is `false` for stable Rust and `true` for both the `ref_pat_eat_one_layer_2024` and
         /// `ref_pat_eat_one_layer_2024_structural` feature gates.
@@ -1069,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 {
                     if !self.tcx.features().mut_ref() {
                         feature_err(
-                            &self.tcx.sess,
+                            self.tcx.sess,
                             sym::mut_ref,
                             pat.span.until(ident.span),
                             "binding cannot be both mutable and by-reference",
@@ -1487,31 +1488,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         opt_def_id: Option<hir::def_id::DefId>,
         ident: Ident,
     ) -> bool {
-        match opt_def_id {
-            Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
-                Some(hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::Const(_, _, _, body_id),
-                    ..
-                })) => match self.tcx.hir_node(body_id.hir_id) {
-                    hir::Node::Expr(expr) => {
-                        if hir::is_range_literal(expr) {
-                            let span = self.tcx.hir_span(body_id.hir_id);
-                            if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
-                                e.span_suggestion_verbose(
-                                    ident.span,
-                                    "you may want to move the range into the match block",
-                                    snip,
-                                    Applicability::MachineApplicable,
-                                );
-                                return true;
-                            }
-                        }
-                    }
-                    _ => (),
-                },
-                _ => (),
-            },
-            _ => (),
+        if let Some(def_id) = opt_def_id
+            && let Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Const(_, _, _, body_id),
+                ..
+            })) = self.tcx.hir_get_if_local(def_id)
+            && let hir::Node::Expr(expr) = self.tcx.hir_node(body_id.hir_id)
+            && hir::is_range_literal(expr)
+        {
+            let span = self.tcx.hir_span(body_id.hir_id);
+            if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
+                e.span_suggestion_verbose(
+                    ident.span,
+                    "you may want to move the range into the match block",
+                    snip,
+                    Applicability::MachineApplicable,
+                );
+                return true;
+            }
         }
         false
     }
@@ -1529,7 +1523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if let Some(span) = self.tcx.hir_res_span(pat_res) {
             e.span_label(span, format!("{} defined here", res.descr()));
-            if let [hir::PathSegment { ident, .. }] = &*segments {
+            if let [hir::PathSegment { ident, .. }] = segments {
                 e.span_label(
                     pat_span,
                     format!(
@@ -1557,17 +1551,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             _ => (None, None),
                         };
 
-                        let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) {
+                        let is_range = matches!(
+                            type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
                             Some(
                                 LangItem::Range
-                                | LangItem::RangeFrom
-                                | LangItem::RangeTo
-                                | LangItem::RangeFull
-                                | LangItem::RangeInclusiveStruct
-                                | LangItem::RangeToInclusive,
-                            ) => true,
-                            _ => false,
-                        };
+                                    | LangItem::RangeFrom
+                                    | LangItem::RangeTo
+                                    | LangItem::RangeFull
+                                    | LangItem::RangeInclusiveStruct
+                                    | LangItem::RangeToInclusive,
+                            )
+                        );
                         if is_range {
                             if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
                                 let msg = "constants only support matching by type, \
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 6192420898f..d01eeb9a4b6 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -1003,8 +1003,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        debug_assert!(!r.is_bound(), "Should not be resolving bound region.");
-        self.fcx.tcx.lifetimes.re_erased
+        match r.kind() {
+            ty::ReBound(..) => r,
+            _ => self.fcx.tcx.lifetimes.re_erased,
+        }
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 6f6666f8c76..1f5c5e74d97 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -47,7 +47,7 @@ interface_out_dir_error =
     failed to find or create the directory specified by `--out-dir`
 
 interface_proc_macro_crate_panic_abort =
-    building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+    building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic
 
 interface_temps_dir_error =
     failed to find or create the directory specified by `--temps-dir`
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 6cefe887530..761a5c80918 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -42,7 +42,6 @@ use rustc_span::{
     DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
     Symbol, sym,
 };
-use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::{solve, traits};
 use tracing::{info, instrument};
 
@@ -282,7 +281,7 @@ fn configure_and_expand(
         feature_err(sess, sym::export_stable, DUMMY_SP, "`sdylib` crate type is unstable").emit();
     }
 
-    if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
+    if is_proc_macro_crate && !sess.panic_strategy().unwinds() {
         sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort);
     }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 7730bddc0f1..800f5efee41 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -772,7 +772,8 @@ fn test_unstable_options_tracking_hash() {
         branch_protection,
         Some(BranchProtection {
             bti: true,
-            pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B })
+            pac_ret: Some(PacRet { leaf: true, pc: true, key: PAuthKey::B }),
+            gcs: true,
         })
     );
     tracked!(codegen_backend, Some("abc".to_string()));
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 26e09c95e76..76ccd12797e 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -386,8 +386,8 @@ fn get_codegen_sysroot(
                 .collect::<Vec<_>>()
                 .join("\n* ");
             let err = format!(
-                "failed to find a `codegen-backends` folder \
-                           in the sysroot candidates:\n* {candidates}"
+                "failed to find a `codegen-backends` folder in the sysroot candidates:\n\
+                 * {candidates}"
             );
             early_dcx.early_fatal(err);
         });
@@ -396,10 +396,8 @@ fn get_codegen_sysroot(
 
     let d = sysroot.read_dir().unwrap_or_else(|e| {
         let err = format!(
-            "failed to load default codegen backend, couldn't \
-                           read `{}`: {}",
+            "failed to load default codegen backend, couldn't read `{}`: {e}",
             sysroot.display(),
-            e
         );
         early_dcx.early_fatal(err);
     });
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index c29ab569f47..f6790f7ed1e 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -599,14 +599,16 @@ impl Cursor<'_> {
             if potential_closing.is_none() {
                 // a less fortunate recovery if all else fails which finds any dashes preceded by whitespace
                 // on a standalone line. Might be wrong.
+                let mut base_index = 0;
                 while let Some(closing) = rest.find("---") {
                     let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1);
                     if rest[preceding_chars_start..closing].chars().all(is_horizontal_whitespace) {
                         // candidate found
-                        potential_closing = Some(closing);
+                        potential_closing = Some(closing + base_index);
                         break;
                     } else {
                         rest = &rest[closing + 3..];
+                        base_index += closing + 3;
                     }
                 }
             }
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index dca22b986ff..b10be22dc38 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -1,11 +1,12 @@
 use rustc_errors::MultiSpan;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{self, Visitor, VisitorExt};
-use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind};
+use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind, find_attr};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
-use rustc_span::{ExpnKind, Span, kw, sym};
+use rustc_span::{ExpnKind, Span, kw};
 
 use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
 use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
@@ -241,7 +242,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                 )
             }
             ItemKind::Macro(_, _macro, _kinds)
-                if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
+                if find_attr!(
+                    cx.tcx.get_all_attrs(item.owner_id.def_id),
+                    AttributeKind::MacroExport { .. }
+                ) =>
             {
                 cx.emit_span_lint(
                     NON_LOCAL_DEFINITIONS,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index b79075ac09b..3d0974d5d28 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -4191,8 +4191,13 @@ declare_lint! {
     /// You can't have multiple arguments in a `#[macro_export(..)]`, or mention arguments other than `local_inner_macros`.
     ///
     pub INVALID_MACRO_EXPORT_ARGUMENTS,
-    Warn,
+    Deny,
     "\"invalid_parameter\" isn't a valid argument for `#[macro_export]`",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseError,
+        reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
+        report_in_deps: true,
+    };
 }
 
 declare_lint! {
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index 0dfd1b13df5..ad93c745381 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -10,8 +10,7 @@ libc = "0.2.73"
 
 [build-dependencies]
 # tidy-alphabetical-start
-# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
-# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa` and `rustc_windows_rc`.
+# `cc` updates often break things, so we pin it here.
 cc = "=1.2.16"
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 7518b40799b..013d68fa3e4 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -359,10 +359,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   return wrap(TM);
 }
 
-extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
-  delete unwrap(TM);
-}
-
 // Unfortunately, the LLVM C API doesn't provide a way to create the
 // TargetLibraryInfo pass, so we use this method to do so.
 extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 64151962321..9953f5e1731 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -553,6 +553,7 @@ enum class LLVMRustMemoryEffects {
   None,
   ReadOnly,
   InaccessibleMemOnly,
+  ReadOnlyNotPure,
 };
 
 extern "C" LLVMAttributeRef
@@ -568,6 +569,10 @@ LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C,
   case LLVMRustMemoryEffects::InaccessibleMemOnly:
     return wrap(Attribute::getWithMemoryEffects(
         *unwrap(C), MemoryEffects::inaccessibleMemOnly()));
+  case LLVMRustMemoryEffects::ReadOnlyNotPure:
+    return wrap(Attribute::getWithMemoryEffects(
+        *unwrap(C),
+        MemoryEffects::readOnly() | MemoryEffects::inaccessibleMemOnly()));
   default:
     report_fatal_error("bad MemoryEffects.");
   }
@@ -1680,6 +1685,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
           RemarkStreamer(std::move(RemarkStreamer)),
           LlvmRemarkStreamer(std::move(LlvmRemarkStreamer)) {}
 
+#if LLVM_VERSION_GE(22, 0)
+    ~RustDiagnosticHandler() {
+      if (RemarkStreamer) {
+        RemarkStreamer->releaseSerializer();
+      }
+    }
+#endif
+
     virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
       // If this diagnostic is one of the optimization remark kinds, we can
       // check if it's enabled before emitting it. This can avoid many
@@ -1774,9 +1787,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
     // Do not delete the file after we gather remarks
     RemarkFile->keep();
 
+#if LLVM_VERSION_GE(22, 0)
+    auto RemarkSerializer = remarks::createRemarkSerializer(
+        llvm::remarks::Format::YAML, RemarkFile->os());
+#else
     auto RemarkSerializer = remarks::createRemarkSerializer(
         llvm::remarks::Format::YAML, remarks::SerializerMode::Separate,
         RemarkFile->os());
+#endif
     if (Error E = RemarkSerializer.takeError()) {
       std::string Error = std::string("Cannot create remark serializer: ") +
                           toString(std::move(E));
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 5821ffa3a30..5d32950875a 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -5,7 +5,7 @@ use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
 use syn::{
     AttrStyle, Attribute, Block, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced,
-    parenthesized, parse_macro_input, parse_quote, token,
+    parenthesized, parse_macro_input, token,
 };
 
 mod kw {
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index e104be2c466..e624bfc5b8b 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -98,6 +98,13 @@ metadata_full_metadata_not_found =
 metadata_global_alloc_required =
     no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
 
+metadata_incompatible_with_immediate_abort =
+    the crate `{$crate_name}` was compiled with a panic strategy which is incompatible with `immediate-abort`
+
+metadata_incompatible_with_immediate_abort_core =
+    the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort`
+    .help = consider building the standard library from source with `cargo build -Zbuild-std`
+
 metadata_incompatible_panic_in_drop_strategy =
     the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 9e23da88f5e..7650acbd292 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1027,6 +1027,10 @@ impl CStore {
         let name = match desired_strategy {
             PanicStrategy::Unwind => sym::panic_unwind,
             PanicStrategy::Abort => sym::panic_abort,
+            PanicStrategy::ImmediateAbort => {
+                // Immediate-aborting panics don't use a runtime.
+                return;
+            }
         };
         info!("panic runtime not found -- loading {}", name);
 
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index fb9c2e23b71..8054a48d37a 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -61,11 +61,13 @@ use rustc_session::config::CrateType;
 use rustc_session::cstore::CrateDepKind;
 use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
 use rustc_span::sym;
+use rustc_target::spec::PanicStrategy;
 use tracing::info;
 
 use crate::creader::CStore;
 use crate::errors::{
-    BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
+    BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy,
+    IncompatibleWithImmediateAbort, IncompatibleWithImmediateAbortCore, LibRequired,
     NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcDriverHelp, RustcLibRequired,
     TwoPanicRuntimes,
 };
@@ -402,15 +404,43 @@ fn activate_injected_dep(
 /// there's only going to be one panic runtime in the output.
 fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
     let sess = &tcx.sess;
+    let list: Vec<_> = list
+        .iter_enumerated()
+        .filter_map(
+            |(cnum, linkage)| if *linkage == Linkage::NotLinked { None } else { Some(cnum) },
+        )
+        .collect();
     if list.is_empty() {
         return;
     }
-    let mut panic_runtime = None;
-    for (cnum, linkage) in list.iter_enumerated() {
-        if let Linkage::NotLinked = *linkage {
-            continue;
+    let desired_strategy = sess.panic_strategy();
+
+    // If we are panic=immediate-abort, make sure everything in the dependency tree has also been
+    // compiled with immediate-abort.
+    if list
+        .iter()
+        .any(|cnum| tcx.required_panic_strategy(*cnum) == Some(PanicStrategy::ImmediateAbort))
+    {
+        let mut invalid_crates = Vec::new();
+        for cnum in list.iter().copied() {
+            if tcx.required_panic_strategy(cnum) != Some(PanicStrategy::ImmediateAbort) {
+                invalid_crates.push(cnum);
+                // If core is incompatible, it's very likely that we'd emit an error for every
+                // sysroot crate, so instead of doing that emit a single fatal error that suggests
+                // using build-std.
+                if tcx.crate_name(cnum) == sym::core {
+                    sess.dcx().emit_fatal(IncompatibleWithImmediateAbortCore);
+                }
+            }
         }
+        for cnum in invalid_crates {
+            sess.dcx()
+                .emit_err(IncompatibleWithImmediateAbort { crate_name: tcx.crate_name(cnum) });
+        }
+    }
 
+    let mut panic_runtime = None;
+    for cnum in list.iter().copied() {
         if tcx.is_panic_runtime(cnum) {
             if let Some((prev, _)) = panic_runtime {
                 let prev_name = tcx.crate_name(prev);
@@ -430,8 +460,6 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
     // only one, but we perform validation here that all the panic strategy
     // compilation modes for the whole DAG are valid.
     if let Some((runtime_cnum, found_strategy)) = panic_runtime {
-        let desired_strategy = sess.panic_strategy();
-
         // First up, validate that our selected panic runtime is indeed exactly
         // our same strategy.
         if found_strategy != desired_strategy {
@@ -445,10 +473,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
         // strategy. If the dep isn't linked, we ignore it, and if our strategy
         // is abort then it's compatible with everything. Otherwise all crates'
         // panic strategy must match our own.
-        for (cnum, linkage) in list.iter_enumerated() {
-            if let Linkage::NotLinked = *linkage {
-                continue;
-            }
+        for cnum in list.iter().copied() {
             if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) {
                 continue;
             }
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index e5a4fd48353..abfd078f746 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -76,6 +76,16 @@ pub struct RequiredPanicStrategy {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_incompatible_with_immediate_abort)]
+pub struct IncompatibleWithImmediateAbort {
+    pub crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_with_immediate_abort_core)]
+pub struct IncompatibleWithImmediateAbortCore;
+
+#[derive(Diagnostic)]
 #[diag(metadata_incompatible_panic_in_drop_strategy)]
 pub struct IncompatiblePanicInDropStrategy {
     pub crate_name: Symbol,
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 279ab9a9d8f..82f3df8da3b 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -98,6 +98,12 @@ middle_layout_references_error =
 middle_layout_size_overflow =
     values of the type `{$ty}` are too big for the target architecture
 
+middle_layout_simd_too_many =
+    the SIMD type `{$ty}` has more elements than the limit {$max_lanes}
+
+middle_layout_simd_zero_length =
+    the SIMD type `{$ty}` has zero elements
+
 middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
 
 middle_layout_unknown =
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index e3e1393b5f9..0be26712b9c 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -143,6 +143,12 @@ pub enum LayoutError<'tcx> {
     #[diag(middle_layout_size_overflow)]
     Overflow { ty: Ty<'tcx> },
 
+    #[diag(middle_layout_simd_too_many)]
+    SimdTooManyLanes { ty: Ty<'tcx>, max_lanes: u64 },
+
+    #[diag(middle_layout_simd_zero_length)]
+    SimdZeroLength { ty: Ty<'tcx> },
+
     #[diag(middle_layout_normalization_failure)]
     NormalizationFailure { ty: Ty<'tcx>, failure_ty: String },
 
diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
index 5a811321f58..a7f0095dcdf 100644
--- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs
+++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
@@ -1,15 +1,9 @@
 use std::path::PathBuf;
 use std::sync::Arc;
 
+use rustc_hir::attrs::DebuggerVisualizerType;
 use rustc_macros::{Decodable, Encodable, HashStable};
 
-#[derive(HashStable)]
-#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
-pub enum DebuggerVisualizerType {
-    Natvis,
-    GdbPrettyPrinter,
-}
-
 /// A single debugger visualizer file.
 #[derive(HashStable)]
 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index 93264f02cc2..a0e4c288c4a 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -98,5 +98,6 @@ pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
             lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo
         }
         PanicStrategy::Unwind => true,
+        PanicStrategy::ImmediateAbort => false,
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 7c72a8ec243..951aac503fe 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -499,10 +499,7 @@ pub enum ValidationErrorKind<'tcx> {
     MutableRefInConst,
     NullFnPtr,
     NeverVal,
-    NullablePtrOutOfRange {
-        range: WrappingRange,
-        max_value: u128,
-    },
+    NonnullPtrMaybeNull,
     PtrOutOfRange {
         range: WrappingRange,
         max_value: u128,
@@ -544,6 +541,8 @@ pub enum ValidationErrorKind<'tcx> {
     },
     NullPtr {
         ptr_kind: PointerKind,
+        /// Records whether this pointer is definitely null or just may be null.
+        maybe: bool,
     },
     DanglingPtrNoProvenance {
         ptr_kind: PointerKind,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index c477e65f5d6..507a25a4325 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -16,7 +16,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
 use rustc_session::config::OptLevel;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 use rustc_target::callconv::FnAbi;
-use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi};
+use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
 use tracing::debug;
 use {rustc_abi as abi, rustc_hir as hir};
 
@@ -219,6 +219,15 @@ impl fmt::Display for ValidityRequirement {
 }
 
 #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
+pub enum SimdLayoutError {
+    /// The vector has 0 lanes.
+    ZeroLength,
+    /// The vector has more lanes than supported or permitted by
+    /// #\[rustc_simd_monomorphize_lane_limit\].
+    TooManyLanes(u64),
+}
+
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
     /// A type doesn't have a sensible layout.
     ///
@@ -230,6 +239,8 @@ pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     /// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
     SizeOverflow(Ty<'tcx>),
+    /// A SIMD vector has invalid layout, such as zero-length or too many lanes.
+    InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError },
     /// The layout can vary due to a generic parameter.
     ///
     /// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
@@ -257,6 +268,10 @@ impl<'tcx> LayoutError<'tcx> {
         match self {
             Unknown(_) => middle_layout_unknown,
             SizeOverflow(_) => middle_layout_size_overflow,
+            InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => {
+                middle_layout_simd_too_many
+            }
+            InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => middle_layout_simd_zero_length,
             TooGeneric(_) => middle_layout_too_generic,
             NormalizationFailure(_, _) => middle_layout_normalization_failure,
             Cycle(_) => middle_layout_cycle,
@@ -271,6 +286,10 @@ impl<'tcx> LayoutError<'tcx> {
         match self {
             Unknown(ty) => E::Unknown { ty },
             SizeOverflow(ty) => E::Overflow { ty },
+            InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
+                E::SimdTooManyLanes { ty, max_lanes }
+            }
+            InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty },
             TooGeneric(ty) => E::TooGeneric { ty },
             NormalizationFailure(ty, e) => {
                 E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
@@ -293,6 +312,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
             LayoutError::SizeOverflow(ty) => {
                 write!(f, "values of the type `{ty}` are too big for the target architecture")
             }
+            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
+                write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}")
+            }
+            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => {
+                write!(f, "the SIMD type `{ty}` has zero elements")
+            }
             LayoutError::NormalizationFailure(t, e) => write!(
                 f,
                 "unable to determine layout for `{}` because `{}` cannot be normalized",
@@ -374,6 +399,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
                 e @ LayoutError::Cycle(_)
                 | e @ LayoutError::Unknown(_)
                 | e @ LayoutError::SizeOverflow(_)
+                | e @ LayoutError::InvalidSimd { .. }
                 | e @ LayoutError::NormalizationFailure(..)
                 | e @ LayoutError::ReferencesError(_),
             ) => return Err(e),
@@ -1198,7 +1224,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         //
         // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
         // function defined in Rust is also required to abort.
-        if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
+        if !tcx.sess.panic_strategy().unwinds() && !tcx.is_foreign_item(did) {
             return false;
         }
 
@@ -1206,7 +1232,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         //
         // This is not part of `codegen_fn_attrs` as it can differ between crates
         // and therefore cannot be computed in core.
-        if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort
+        if !tcx.sess.opts.unstable_opts.panic_in_drop.unwinds()
             && tcx.is_lang_item(did, LangItem::DropInPlace)
         {
             return false;
@@ -1245,7 +1271,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         | RiscvInterruptS
         | RustInvalid
         | Unadjusted => false,
-        Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
+        Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(),
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 1b7ef8de845..8f7c8170f7a 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3177,8 +3177,7 @@ define_print! {
                 write!(p, "` can be evaluated")?;
             }
             ty::ClauseKind::UnstableFeature(symbol) => {
-                write!(p, "unstable feature: ")?;
-                write!(p, "`{symbol}`")?;
+                write!(p, "feature({symbol}) is enabled")?;
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4f039381e50..a4422abc688 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1368,7 +1368,6 @@ impl<'tcx> Ty<'tcx> {
     /// 2229 drop reorder migration analysis.
     #[inline]
     pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
-        assert!(!self.has_non_region_infer());
         // Avoid querying in simple cases.
         match needs_drop_components(tcx, self) {
             Err(AlwaysRequiresDrop) => true,
@@ -1381,6 +1380,16 @@ impl<'tcx> Ty<'tcx> {
                     _ => self,
                 };
 
+                // FIXME
+                // We should be canonicalizing, or else moving this to a method of inference
+                // context, or *something* like that,
+                // but for now just avoid passing inference variables
+                // to queries that can't cope with them.
+                // Instead, conservatively return "true" (may change drop order).
+                if query_ty.has_infer() {
+                    return true;
+                }
+
                 // This doesn't depend on regions, so try to minimize distinct
                 // query keys used.
                 let erased = tcx.normalize_erasing_regions(typing_env, query_ty);
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
index a4ef6e92739..3a5839f2d40 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
@@ -8,6 +8,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
+use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::cast::{CastTy, mir_cast_kind};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, Ty, UpvarArgs};
@@ -656,6 +657,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         block.and(rvalue)
     }
 
+    /// Recursively inspect a THIR expression and probe through unsizing
+    /// operations that can be const-folded today.
+    fn check_constness(&self, mut kind: &'a ExprKind<'tcx>) -> bool {
+        loop {
+            debug!(?kind, "check_constness");
+            match kind {
+                &ExprKind::ValueTypeAscription { source: eid, user_ty: _, user_ty_span: _ }
+                | &ExprKind::Use { source: eid }
+                | &ExprKind::PointerCoercion {
+                    cast: PointerCoercion::Unsize,
+                    source: eid,
+                    is_from_as_cast: _,
+                }
+                | &ExprKind::Scope { region_scope: _, lint_level: _, value: eid } => {
+                    kind = &self.thir[eid].kind
+                }
+                _ => return matches!(Category::of(&kind), Some(Category::Constant)),
+            }
+        }
+    }
+
     fn build_zero_repeat(
         &mut self,
         mut block: BasicBlock,
@@ -666,7 +688,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let this = self;
         let value_expr = &this.thir[value];
         let elem_ty = value_expr.ty;
-        if let Some(Category::Constant) = Category::of(&value_expr.kind) {
+        if this.check_constness(&value_expr.kind) {
             // Repeating a const does nothing
         } else {
             // For a non-const, we may need to generate an appropriate `Drop`
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index c1cd2788348..c5cd06f170c 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -86,7 +86,6 @@ use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::source_map::dummy_spanned;
 use rustc_span::symbol::sym;
 use rustc_span::{DUMMY_SP, Span};
-use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::TyCtxtInferExt as _;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
@@ -1149,7 +1148,7 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing
 
 fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
     // Nothing can unwind when landing pads are off.
-    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
+    if !tcx.sess.panic_strategy().unwinds() {
         return false;
     }
 
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index abbff1c48dd..7c66783548e 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -101,12 +101,15 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
 }
 
 fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrategy> {
+    let local_strategy = tcx.sess.panic_strategy();
+
     if tcx.is_panic_runtime(LOCAL_CRATE) {
-        return Some(tcx.sess.panic_strategy());
+        return Some(local_strategy);
     }
 
-    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
-        return Some(PanicStrategy::Abort);
+    match local_strategy {
+        PanicStrategy::Abort | PanicStrategy::ImmediateAbort => return Some(local_strategy),
+        _ => {}
     }
 
     for def_id in tcx.hir_body_owners() {
diff --git a/compiler/rustc_mir_transform/src/impossible_predicates.rs b/compiler/rustc_mir_transform/src/impossible_predicates.rs
index b03518de00a..883ee32bdec 100644
--- a/compiler/rustc_mir_transform/src/impossible_predicates.rs
+++ b/compiler/rustc_mir_transform/src/impossible_predicates.rs
@@ -28,6 +28,7 @@
 
 use rustc_middle::mir::{Body, START_BLOCK, TerminatorKind};
 use rustc_middle::ty::{TyCtxt, TypeFlags, TypeVisitableExt};
+use rustc_span::def_id::DefId;
 use rustc_trait_selection::traits;
 use tracing::trace;
 
@@ -35,23 +36,29 @@ use crate::pass_manager::MirPass;
 
 pub(crate) struct ImpossiblePredicates;
 
+fn has_impossible_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx);
+    tracing::trace!(?predicates);
+    let predicates = predicates.predicates.into_iter().filter(|p| {
+        !p.has_type_flags(
+            // Only consider global clauses to simplify.
+            TypeFlags::HAS_FREE_LOCAL_NAMES
+                // Clauses that refer to unevaluated constants as they cause cycles.
+                | TypeFlags::HAS_CT_PROJECTION,
+        )
+    });
+    let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect();
+    tracing::trace!(?predicates);
+    predicates.references_error() || traits::impossible_predicates(tcx, predicates)
+}
+
 impl<'tcx> MirPass<'tcx> for ImpossiblePredicates {
     #[tracing::instrument(level = "trace", skip(self, tcx, body))]
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         tracing::trace!(def_id = ?body.source.def_id());
-        let predicates = tcx.predicates_of(body.source.def_id()).instantiate_identity(tcx);
-        tracing::trace!(?predicates);
-        let predicates = predicates.predicates.into_iter().filter(|p| {
-            !p.has_type_flags(
-                // Only consider global clauses to simplify.
-                TypeFlags::HAS_FREE_LOCAL_NAMES
-                // Clauses that refer to unevaluated constants as they cause cycles.
-                | TypeFlags::HAS_CT_PROJECTION,
-            )
-        });
-        let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect();
-        tracing::trace!(?predicates);
-        if predicates.references_error() || traits::impossible_predicates(tcx, predicates) {
+        let impossible = body.tainted_by_errors.is_some()
+            || has_impossible_predicates(tcx, body.source.def_id());
+        if impossible {
             trace!("found unsatisfiable predicates");
             // Clear the body to only contain a single `unreachable` statement.
             let bbs = body.basic_blocks.as_mut();
diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs
index c781d1a5324..d831ab50b1a 100644
--- a/compiler/rustc_mir_transform/src/patch.rs
+++ b/compiler/rustc_mir_transform/src/patch.rs
@@ -1,4 +1,5 @@
-use rustc_index::{Idx, IndexVec};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::Idx;
 use rustc_middle::mir::*;
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
@@ -9,7 +10,7 @@ use tracing::debug;
 /// and replacement of terminators, and then apply the queued changes all at
 /// once with `apply`. This is useful for MIR transformation passes.
 pub(crate) struct MirPatch<'tcx> {
-    term_patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
+    term_patch_map: FxHashMap<BasicBlock, TerminatorKind<'tcx>>,
     new_blocks: Vec<BasicBlockData<'tcx>>,
     new_statements: Vec<(Location, StatementKind<'tcx>)>,
     new_locals: Vec<LocalDecl<'tcx>>,
@@ -22,17 +23,21 @@ pub(crate) struct MirPatch<'tcx> {
     terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
     body_span: Span,
     next_local: usize,
+    /// The number of blocks at the start of the transformation. New blocks
+    /// get appended at the end.
+    next_block: usize,
 }
 
 impl<'tcx> MirPatch<'tcx> {
     /// Creates a new, empty patch.
     pub(crate) fn new(body: &Body<'tcx>) -> Self {
         let mut result = MirPatch {
-            term_patch_map: IndexVec::from_elem(None, &body.basic_blocks),
+            term_patch_map: Default::default(),
             new_blocks: vec![],
             new_statements: vec![],
             new_locals: vec![],
             next_local: body.local_decls.len(),
+            next_block: body.basic_blocks.len(),
             resume_block: None,
             unreachable_cleanup_block: None,
             unreachable_no_cleanup_block: None,
@@ -141,7 +146,7 @@ impl<'tcx> MirPatch<'tcx> {
 
     /// Has a replacement of this block's terminator been queued in this patch?
     pub(crate) fn is_term_patched(&self, bb: BasicBlock) -> bool {
-        self.term_patch_map[bb].is_some()
+        self.term_patch_map.contains_key(&bb)
     }
 
     /// Universal getter for block data, either it is in 'old' blocks or in patched ones
@@ -194,18 +199,17 @@ impl<'tcx> MirPatch<'tcx> {
 
     /// Queues the addition of a new basic block.
     pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
-        let block = self.term_patch_map.next_index();
+        let block = BasicBlock::from_usize(self.next_block + self.new_blocks.len());
         debug!("MirPatch: new_block: {:?}: {:?}", block, data);
         self.new_blocks.push(data);
-        self.term_patch_map.push(None);
         block
     }
 
     /// Queues the replacement of a block's terminator.
     pub(crate) fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) {
-        assert!(self.term_patch_map[block].is_none());
+        assert!(!self.term_patch_map.contains_key(&block));
         debug!("MirPatch: patch_terminator({:?}, {:?})", block, new);
-        self.term_patch_map[block] = Some(new);
+        self.term_patch_map.insert(block, new);
     }
 
     /// Queues the insertion of a statement at a given location. The statement
@@ -244,6 +248,7 @@ impl<'tcx> MirPatch<'tcx> {
             self.new_blocks.len(),
             body.basic_blocks.len()
         );
+        debug_assert_eq!(self.next_block, body.basic_blocks.len());
         let bbs = if self.term_patch_map.is_empty() && self.new_blocks.is_empty() {
             body.basic_blocks.as_mut_preserves_cfg()
         } else {
@@ -251,11 +256,12 @@ impl<'tcx> MirPatch<'tcx> {
         };
         bbs.extend(self.new_blocks);
         body.local_decls.extend(self.new_locals);
-        for (src, patch) in self.term_patch_map.into_iter_enumerated() {
-            if let Some(patch) = patch {
-                debug!("MirPatch: patching block {:?}", src);
-                bbs[src].terminator_mut().kind = patch;
-            }
+
+        // The order in which we patch terminators does not change the result.
+        #[allow(rustc::potential_query_instability)]
+        for (src, patch) in self.term_patch_map {
+            debug!("MirPatch: patching block {:?}", src);
+            bbs[src].terminator_mut().kind = patch;
         }
 
         let mut new_statements = self.new_statements;
@@ -273,8 +279,8 @@ impl<'tcx> MirPatch<'tcx> {
             }
             debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta);
             loc.statement_index += delta;
-            let source_info = Self::source_info_for_index(&body[loc.block], loc);
-            body[loc.block]
+            let source_info = Self::source_info_for_index(&bbs[loc.block], loc);
+            bbs[loc.block]
                 .statements
                 .insert(loc.statement_index, Statement::new(source_info, stmt));
             delta += 1;
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 5b6d7ffb511..b53c1f6d202 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -1,7 +1,6 @@
 use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
-use rustc_target::spec::PanicStrategy;
 use tracing::debug;
 
 use crate::patch::MirPatch;
@@ -13,7 +12,7 @@ pub(super) struct RemoveNoopLandingPads;
 
 impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.panic_strategy() != PanicStrategy::Abort
+        sess.panic_strategy().unwinds()
     }
 
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 75537caa894..870e0a90b54 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -93,15 +93,6 @@ passes_dead_codes =
        }
     } never {$participle}
 
-passes_debug_visualizer_invalid =
-    invalid argument
-    .note_1 = expected: `natvis_file = "..."`
-    .note_2 = OR
-    .note_3 = expected: `gdb_script_file = "..."`
-
-passes_debug_visualizer_placement =
-    attribute should be applied to a module
-
 passes_debug_visualizer_unreadable =
     couldn't read {$file}: {$error}
 
@@ -349,10 +340,6 @@ passes_invalid_attr_at_crate_level =
 passes_invalid_attr_at_crate_level_item =
     the inner attribute doesn't annotate this {$kind}
 
-passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument
-
-passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
-
 passes_lang_item_fn = {$name ->
     [panic_impl] `#[panic_handler]`
     *[other] `{$name}` lang item
@@ -392,9 +379,6 @@ passes_loop_match_attr =
     `#[loop_match]` should be applied to a loop
     .label = not a loop
 
-passes_macro_export =
-    `#[macro_export]` only has an effect on macro definitions
-
 passes_macro_export_on_decl_macro =
     `#[macro_export]` has no effect on declarative macro definitions
     .note = declarative macros follow the same exporting rules as regular items
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 4d5a8447695..007353f136d 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -38,8 +38,8 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::config::CrateType;
 use rustc_session::lint;
 use rustc_session::lint::builtin::{
-    CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
-    MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
+    CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+    MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::edition::Edition;
@@ -217,7 +217,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 },
                 Attribute::Parsed(AttributeKind::Link(_, attr_span)) => {
                     self.check_link(hir_id, *attr_span, span, target)
-                }
+                },
+                Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => {
+                    self.check_macro_export(hir_id, *span, target)
+                },
                 Attribute::Parsed(
                     AttributeKind::BodyStability { .. }
                     | AttributeKind::ConstStabilityIndirect
@@ -253,6 +256,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::MacroEscape( .. )
                     | AttributeKind::RustcLayoutScalarValidRangeStart(..)
                     | AttributeKind::RustcLayoutScalarValidRangeEnd(..)
+                    | AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
                     | AttributeKind::ExportStable
                     | AttributeKind::FfiConst(..)
                     | AttributeKind::UnstableFeatureBound(..)
@@ -278,6 +282,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::ObjcClass { .. }
                     | AttributeKind::ObjcSelector { .. }
                     | AttributeKind::RustcCoherenceIsCore(..)
+                    | AttributeKind::DebuggerVisualizer(..)
                 ) => { /* do nothing  */ }
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
@@ -298,7 +303,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             &mut doc_aliases,
                         ),
                         [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
-                        [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
                         [sym::rustc_no_implicit_autorefs, ..] => {
                             self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
@@ -331,7 +335,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::rustc_has_incoherent_inherent_impls, ..] => {
                             self.check_has_incoherent_inherent_impls(attr, span, target)
                         }
-                        [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
                         [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
                             self.check_autodiff(hir_id, attr, span, target)
                         }
@@ -1780,20 +1783,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
-    fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
-        // Here we only check that the #[debugger_visualizer] attribute is attached
-        // to nothing other than a module. All other checks are done in the
-        // `debugger_visualizer` query where they need to be done for decoding
-        // anyway.
-        match target {
-            Target::Mod => {}
-            _ => {
-                self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() });
-            }
-        }
-    }
-
     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
     /// (Allows proc_macro functions)
     fn check_rustc_allow_const_fn_unstable(
@@ -1850,45 +1839,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
+    fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) {
         if target != Target::MacroDef {
+            return;
+        }
+
+        // special case when `#[macro_export]` is applied to a macro 2.0
+        let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
+        let is_decl_macro = !macro_definition.macro_rules;
+
+        if is_decl_macro {
             self.tcx.emit_node_span_lint(
                 UNUSED_ATTRIBUTES,
                 hir_id,
-                attr.span(),
-                errors::MacroExport::Normal,
+                attr_span,
+                errors::MacroExport::OnDeclMacro,
             );
-        } else if let Some(meta_item_list) = attr.meta_item_list()
-            && !meta_item_list.is_empty()
-        {
-            if meta_item_list.len() > 1 {
-                self.tcx.emit_node_span_lint(
-                    INVALID_MACRO_EXPORT_ARGUMENTS,
-                    hir_id,
-                    attr.span(),
-                    errors::MacroExport::TooManyItems,
-                );
-            } else if !meta_item_list[0].has_name(sym::local_inner_macros) {
-                self.tcx.emit_node_span_lint(
-                    INVALID_MACRO_EXPORT_ARGUMENTS,
-                    hir_id,
-                    meta_item_list[0].span(),
-                    errors::MacroExport::InvalidArgument,
-                );
-            }
-        } else {
-            // special case when `#[macro_export]` is applied to a macro 2.0
-            let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
-            let is_decl_macro = !macro_definition.macro_rules;
-
-            if is_decl_macro {
-                self.tcx.emit_node_span_lint(
-                    UNUSED_ATTRIBUTES,
-                    hir_id,
-                    attr.span(),
-                    errors::MacroExport::OnDeclMacro,
-                );
-            }
         }
     }
 
@@ -2253,7 +2219,9 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         // In the long run, the checks should be harmonized.
         if let ItemKind::Macro(_, macro_def, _) = item.kind {
             let def_id = item.owner_id.to_def_id();
-            if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
+            if macro_def.macro_rules
+                && !find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. })
+            {
                 check_non_exported_macro_for_invalid_attrs(self.tcx, item);
             }
         }
@@ -2384,7 +2352,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
     // which were unsuccessfully resolved due to cannot determine
     // resolution for the attribute macro error.
     const ATTRS_TO_CHECK: &[Symbol] = &[
-        sym::macro_export,
         sym::rustc_main,
         sym::derive,
         sym::test,
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 7a7a8175e55..7211f3cf85b 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -1,67 +1,60 @@
 //! Detecting usage of the `#[debugger_visualizer]` attribute.
 
-use rustc_ast::Attribute;
+use rustc_ast::ast::NodeId;
+use rustc_ast::{HasNodeId, ItemKind, ast};
+use rustc_attr_parsing::AttributeParser;
 use rustc_expand::base::resolve_path;
-use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_hir::Attribute;
+use rustc_hir::attrs::{AttributeKind, DebugVisualizer};
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::query::{LocalCrate, Providers};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::sym;
+use rustc_span::{DUMMY_SP, Span, sym};
 
-use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
+use crate::errors::DebugVisualizerUnreadable;
 
 impl DebuggerVisualizerCollector<'_> {
-    fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
-        if attr.has_name(sym::debugger_visualizer) {
-            let Some(hints) = attr.meta_item_list() else {
-                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
-                return;
-            };
+    fn check_for_debugger_visualizer(
+        &mut self,
+        attrs: &[ast::Attribute],
+        span: Span,
+        node_id: NodeId,
+    ) {
+        if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) =
+            AttributeParser::parse_limited(
+                &self.sess,
+                attrs,
+                sym::debugger_visualizer,
+                span,
+                node_id,
+                None,
+            )
+        {
+            for DebugVisualizer { span, visualizer_type, path } in visualizers {
+                let file = match resolve_path(&self.sess, path.as_str(), span) {
+                    Ok(file) => file,
+                    Err(err) => {
+                        err.emit();
+                        return;
+                    }
+                };
 
-            let [hint] = hints.as_slice() else {
-                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
-                return;
-            };
-
-            let Some(meta_item) = hint.meta_item() else {
-                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
-                return;
-            };
-
-            let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str())
-            {
-                (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value),
-                (Some(sym::gdb_script_file), Some(value)) => {
-                    (DebuggerVisualizerType::GdbPrettyPrinter, value)
-                }
-                (_, _) => {
-                    self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
-                    return;
-                }
-            };
-
-            let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
-                Ok(file) => file,
-                Err(err) => {
-                    err.emit();
-                    return;
-                }
-            };
-
-            match self.sess.source_map().load_binary_file(&file) {
-                Ok((source, _)) => {
-                    self.visualizers.push(DebuggerVisualizerFile::new(
-                        source,
-                        visualizer_type,
-                        file,
-                    ));
-                }
-                Err(error) => {
-                    self.sess.dcx().emit_err(DebugVisualizerUnreadable {
-                        span: meta_item.span,
-                        file: &file,
-                        error,
-                    });
+                match self.sess.source_map().load_binary_file(&file) {
+                    Ok((source, _)) => {
+                        self.visualizers.push(DebuggerVisualizerFile::new(
+                            source,
+                            visualizer_type,
+                            file,
+                        ));
+                    }
+                    Err(error) => {
+                        self.sess.dcx().emit_err(DebugVisualizerUnreadable {
+                            span,
+                            file: &file,
+                            error,
+                        });
+                    }
                 }
             }
         }
@@ -74,9 +67,15 @@ struct DebuggerVisualizerCollector<'a> {
 }
 
 impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
-    fn visit_attribute(&mut self, attr: &'ast Attribute) {
-        self.check_for_debugger_visualizer(attr);
-        rustc_ast::visit::walk_attribute(self, attr);
+    fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result {
+        if let ItemKind::Mod(..) = item.kind {
+            self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id());
+        }
+        rustc_ast::visit::walk_item(self, item);
+    }
+    fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result {
+        self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id);
+        rustc_ast::visit::walk_crate(self, krate);
     }
 }
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 2da4b6f52cf..cfd6b9e6dff 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -476,23 +476,6 @@ pub(crate) struct MacroOnlyAttribute {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_debug_visualizer_placement)]
-pub(crate) struct DebugVisualizerPlacement {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_debug_visualizer_invalid)]
-#[note(passes_note_1)]
-#[note(passes_note_2)]
-#[note(passes_note_3)]
-pub(crate) struct DebugVisualizerInvalid {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_debug_visualizer_unreadable)]
 pub(crate) struct DebugVisualizerUnreadable<'a> {
     #[primary_span]
@@ -530,18 +513,9 @@ pub(crate) struct RustcForceInlineCoro {
 
 #[derive(LintDiagnostic)]
 pub(crate) enum MacroExport {
-    #[diag(passes_macro_export)]
-    Normal,
-
     #[diag(passes_macro_export_on_decl_macro)]
     #[note]
     OnDeclMacro,
-
-    #[diag(passes_invalid_macro_export_arguments)]
-    InvalidArgument,
-
-    #[diag(passes_invalid_macro_export_arguments_too_many_items)]
-    TooManyItems,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index fa3c06059b3..c10b6ca7e71 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -5,7 +5,6 @@
 //! unexpanded macros in the fragment are visited and registered.
 //! Imports are also considered items and placed into modules here, but not resolved yet.
 
-use std::cell::Cell;
 use std::sync::Arc;
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
@@ -35,6 +34,7 @@ use crate::Namespace::{MacroNS, TypeNS, ValueNS};
 use crate::def_collector::collect_definitions;
 use crate::imports::{ImportData, ImportKind};
 use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
+use crate::ref_mut::CmCell;
 use crate::{
     BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot,
     NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used,
@@ -87,7 +87,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // because they can be fetched by glob imports from those modules, and bring traits
         // into scope both directly and through glob imports.
         let key = BindingKey::new_disambiguated(ident, ns, || {
-            parent.underscore_disambiguator.update(|d| d + 1);
+            // FIXME(batched): Will be fixed in batched resolution.
+            parent.underscore_disambiguator.update_unchecked(|d| d + 1);
             parent.underscore_disambiguator.get()
         });
         if self
@@ -477,7 +478,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             kind,
             parent_scope: self.parent_scope,
             module_path,
-            imported_module: Cell::new(None),
+            imported_module: CmCell::new(None),
             span,
             use_span: item.span,
             use_span_with_attributes: item.span_with_attributes(),
@@ -505,7 +506,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                     });
                 }
             }
-            ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import),
+            ImportKind::Glob { .. } => current_module.globs.borrow_mut(self.r).push(import),
             _ => unreachable!(),
         }
     }
@@ -668,7 +669,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             }
             ast::UseTreeKind::Glob => {
                 if !ast::attr::contains_name(&item.attrs, sym::prelude_import) {
-                    let kind = ImportKind::Glob { max_vis: Cell::new(None), id };
+                    let kind = ImportKind::Glob { max_vis: CmCell::new(None), id };
                     self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
                 } else {
                     // Resolve the prelude import early.
@@ -971,7 +972,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id },
             root_id: item.id,
             parent_scope: self.parent_scope,
-            imported_module: Cell::new(module),
+            imported_module: CmCell::new(module),
             has_attributes: !item.attrs.is_empty(),
             use_span_with_attributes: item.span_with_attributes(),
             use_span: item.span,
@@ -1103,7 +1104,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 kind: ImportKind::MacroUse { warn_private },
                 root_id: item.id,
                 parent_scope: this.parent_scope,
-                imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
+                imported_module: CmCell::new(Some(ModuleOrUniformRoot::Module(module))),
                 use_span_with_attributes: item.span_with_attributes(),
                 has_attributes: !item.attrs.is_empty(),
                 use_span: item.span,
@@ -1196,7 +1197,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
     /// directly into its parent scope's module.
     fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> {
         let invoc_id = self.visit_invoc(id);
-        self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
+        self.parent_scope.module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id);
         self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
     }
 
@@ -1274,7 +1275,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                     kind: ImportKind::MacroExport,
                     root_id: item.id,
                     parent_scope: self.parent_scope,
-                    imported_module: Cell::new(None),
+                    imported_module: CmCell::new(None),
                     has_attributes: false,
                     use_span_with_attributes: span,
                     use_span: span,
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 35051675fd8..51489019950 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -492,14 +492,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         _ => Err(Determinacy::Determined),
                     },
                     Scope::Module(module, derive_fallback_lint_id) => {
-                        // FIXME: use `finalize_scope` here.
                         let (adjusted_parent_scope, adjusted_finalize) =
                             if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) {
-                                (parent_scope, finalize)
+                                (parent_scope, finalize_scope!())
                             } else {
                                 (
                                     &ParentScope { module, ..*parent_scope },
-                                    finalize.map(|f| Finalize { used: Used::Scope, ..f }),
+                                    finalize_scope!().map(|f| Finalize { used: Used::Scope, ..f }),
                                 )
                             };
                         let binding = this.reborrow().resolve_ident_in_module_unadjusted(
@@ -557,8 +556,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         None => Err(Determinacy::Determined),
                     },
                     Scope::ExternPreludeItems => {
-                        // FIXME: use `finalize_scope` here.
-                        match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) {
+                        match this
+                            .reborrow()
+                            .extern_prelude_get_item(ident, finalize_scope!().is_some())
+                        {
                             Some(binding) => {
                                 extern_prelude_item_binding = Some(binding);
                                 Ok((binding, Flags::empty()))
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 33c2c7436d1..ce90a1bcd31 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1,6 +1,5 @@
 //! A bunch of methods and structures more or less related to resolving imports.
 
-use std::cell::Cell;
 use std::mem;
 
 use rustc_ast::NodeId;
@@ -32,6 +31,7 @@ use crate::errors::{
     CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
     ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate,
 };
+use crate::ref_mut::CmCell;
 use crate::{
     AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion,
     Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope,
@@ -68,7 +68,7 @@ pub(crate) enum ImportKind<'ra> {
         /// It will directly use `source` when the format is `use prefix::source`.
         target: Ident,
         /// Bindings introduced by the import.
-        bindings: PerNS<Cell<PendingBinding<'ra>>>,
+        bindings: PerNS<CmCell<PendingBinding<'ra>>>,
         /// `true` for `...::{self [as target]}` imports, `false` otherwise.
         type_ns_only: bool,
         /// Did this import result from a nested import? ie. `use foo::{bar, baz};`
@@ -89,7 +89,7 @@ pub(crate) enum ImportKind<'ra> {
     Glob {
         // The visibility of the greatest re-export.
         // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
-        max_vis: Cell<Option<Visibility>>,
+        max_vis: CmCell<Option<Visibility>>,
         id: NodeId,
     },
     ExternCrate {
@@ -182,7 +182,7 @@ pub(crate) struct ImportData<'ra> {
     /// |`use ::foo`      | `ModuleOrUniformRoot::ExternPrelude`          | 2018+ editions |
     /// |`use ::foo`      | `ModuleOrUniformRoot::ModuleAndExternPrelude` | a special case in 2015 edition |
     /// |`use foo`        | `ModuleOrUniformRoot::CurrentScope`           | - |
-    pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
+    pub imported_module: CmCell<Option<ModuleOrUniformRoot<'ra>>>,
     pub vis: Visibility,
 
     /// Span of the visibility.
@@ -320,7 +320,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             && (vis == import_vis
                 || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)))
         {
-            max_vis.set(Some(vis.expect_local()))
+            // FIXME(batched): Will be fixed in batched import resolution.
+            max_vis.set_unchecked(Some(vis.expect_local()))
         }
 
         self.arenas.alloc_name_binding(NameBindingData {
@@ -349,7 +350,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // because they can be fetched by glob imports from those modules, and bring traits
         // into scope both directly and through glob imports.
         let key = BindingKey::new_disambiguated(ident, ns, || {
-            module.underscore_disambiguator.update(|d| d + 1);
+            // FIXME(batched): Will be fixed in batched resolution.
+            module.underscore_disambiguator.update_unchecked(|d| d + 1);
             module.underscore_disambiguator.get()
         });
         self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| {
@@ -482,7 +484,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             }
         };
 
-        let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else {
+        let Ok(glob_importers) = module.glob_importers.try_borrow_mut_unchecked() else {
             return t;
         };
 
@@ -862,7 +864,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             }
         };
 
-        import.imported_module.set(Some(module));
+        // FIXME(batched): Will be fixed in batched import resolution.
+        import.imported_module.set_unchecked(Some(module));
         let (source, target, bindings, type_ns_only) = match import.kind {
             ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => {
                 (source, target, bindings, type_ns_only)
@@ -937,7 +940,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         PendingBinding::Pending
                     }
                 };
-                bindings[ns].set(binding);
+                // FIXME(batched): Will be fixed in batched import resolution.
+                bindings[ns].set_unchecked(binding);
             }
         });
 
@@ -1508,7 +1512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
 
         // Add to module's glob_importers
-        module.glob_importers.borrow_mut().push(import);
+        module.glob_importers.borrow_mut_unchecked().push(import);
 
         // Ensure that `resolutions` isn't borrowed during `try_define`,
         // since it might get updated via a glob cycle.
@@ -1550,7 +1554,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     // reporting conflicts, and reporting unresolved imports.
     fn finalize_resolutions_in(&mut self, module: Module<'ra>) {
         // Since import resolution is finished, globs will not define any more names.
-        *module.globs.borrow_mut() = Vec::new();
+        *module.globs.borrow_mut(self) = Vec::new();
 
         let Some(def_id) = module.opt_def_id() else { return };
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 8b185ce7ef2..8959068b2a6 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -19,6 +19,7 @@
 #![feature(default_field_values)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
+#![feature(ptr_as_ref_unchecked)]
 #![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
 #![recursion_limit = "256"]
@@ -26,7 +27,7 @@
 
 use std::cell::{Cell, Ref, RefCell};
 use std::collections::BTreeSet;
-use std::fmt;
+use std::fmt::{self};
 use std::sync::Arc;
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
@@ -95,6 +96,8 @@ pub mod rustdoc;
 
 pub use macros::registered_tools_ast;
 
+use crate::ref_mut::{CmCell, CmRefCell};
+
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 #[derive(Debug)]
@@ -592,22 +595,22 @@ struct ModuleData<'ra> {
     /// Resolutions in modules from other crates are not populated until accessed.
     lazy_resolutions: Resolutions<'ra>,
     /// True if this is a module from other crate that needs to be populated on access.
-    populate_on_access: Cell<bool>,
+    populate_on_access: Cell<bool>, // FIXME(parallel): Use an atomic in parallel import resolution
     /// Used to disambiguate underscore items (`const _: T = ...`) in the module.
-    underscore_disambiguator: Cell<u32>,
+    underscore_disambiguator: CmCell<u32>,
 
     /// Macro invocations that can expand into items in this module.
-    unexpanded_invocations: RefCell<FxHashSet<LocalExpnId>>,
+    unexpanded_invocations: CmRefCell<FxHashSet<LocalExpnId>>,
 
     /// Whether `#[no_implicit_prelude]` is active.
     no_implicit_prelude: bool,
 
-    glob_importers: RefCell<Vec<Import<'ra>>>,
-    globs: RefCell<Vec<Import<'ra>>>,
+    glob_importers: CmRefCell<Vec<Import<'ra>>>,
+    globs: CmRefCell<Vec<Import<'ra>>>,
 
     /// Used to memoize the traits in this module for faster searches through all traits in scope.
     traits:
-        RefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>,
+        CmRefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>,
 
     /// Span of the module itself. Used for error reporting.
     span: Span,
@@ -656,12 +659,12 @@ impl<'ra> ModuleData<'ra> {
             kind,
             lazy_resolutions: Default::default(),
             populate_on_access: Cell::new(is_foreign),
-            underscore_disambiguator: Cell::new(0),
+            underscore_disambiguator: CmCell::new(0),
             unexpanded_invocations: Default::default(),
             no_implicit_prelude,
-            glob_importers: RefCell::new(Vec::new()),
-            globs: RefCell::new(Vec::new()),
-            traits: RefCell::new(None),
+            glob_importers: CmRefCell::new(Vec::new()),
+            globs: CmRefCell::new(Vec::new()),
+            traits: CmRefCell::new(None),
             span,
             expansion,
             self_binding,
@@ -696,7 +699,7 @@ impl<'ra> Module<'ra> {
 
     /// This modifies `self` in place. The traits will be stored in `self.traits`.
     fn ensure_traits<'tcx>(self, resolver: &impl AsRef<Resolver<'ra, 'tcx>>) {
-        let mut traits = self.traits.borrow_mut();
+        let mut traits = self.traits.borrow_mut(resolver.as_ref());
         if traits.is_none() {
             let mut collected_traits = Vec::new();
             self.for_each_child(resolver, |r, name, ns, binding| {
@@ -1974,6 +1977,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
     fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> {
         if module.populate_on_access.get() {
+            // FIXME(batched): Will be fixed in batched import resolution.
             module.populate_on_access.set(false);
             self.build_reduced_graph_external(module);
         }
@@ -2504,9 +2508,20 @@ pub fn provide(providers: &mut Providers) {
     providers.registered_tools = macros::registered_tools;
 }
 
+/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions.
+///
+/// `Cm` stands for "conditionally mutable".
+///
+/// Prefer constructing it through [`Resolver::cm`] to ensure correctness.
+type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>;
+
 mod ref_mut {
+    use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut};
+    use std::fmt;
     use std::ops::Deref;
 
+    use crate::Resolver;
+
     /// A wrapper around a mutable reference that conditionally allows mutable access.
     pub(crate) struct RefOrMut<'a, T> {
         p: &'a mut T,
@@ -2555,11 +2570,86 @@ mod ref_mut {
             self.p
         }
     }
-}
 
-/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions.
-///
-/// `Cm` stands for "conditionally mutable".
-///
-/// Prefer constructing it through [`Resolver::cm`] to ensure correctness.
-type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>;
+    /// A wrapper around a [`Cell`] that only allows mutation based on a condition in the resolver.
+    #[derive(Default)]
+    pub(crate) struct CmCell<T>(Cell<T>);
+
+    impl<T: Copy + fmt::Debug> fmt::Debug for CmCell<T> {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.debug_tuple("CmCell").field(&self.get()).finish()
+        }
+    }
+
+    impl<T: Copy> Clone for CmCell<T> {
+        #[inline]
+        fn clone(&self) -> CmCell<T> {
+            CmCell::new(self.get())
+        }
+    }
+
+    impl<T: Copy> CmCell<T> {
+        pub(crate) const fn get(&self) -> T {
+            self.0.get()
+        }
+
+        pub(crate) fn update_unchecked(&self, f: impl FnOnce(T) -> T)
+        where
+            T: Copy,
+        {
+            let old = self.get();
+            self.set_unchecked(f(old));
+        }
+    }
+
+    impl<T> CmCell<T> {
+        pub(crate) const fn new(value: T) -> CmCell<T> {
+            CmCell(Cell::new(value))
+        }
+
+        pub(crate) fn set_unchecked(&self, val: T) {
+            self.0.set(val);
+        }
+
+        pub(crate) fn into_inner(self) -> T {
+            self.0.into_inner()
+        }
+    }
+
+    /// A wrapper around a [`RefCell`] that only allows mutable borrows based on a condition in the resolver.
+    #[derive(Default)]
+    pub(crate) struct CmRefCell<T>(RefCell<T>);
+
+    impl<T> CmRefCell<T> {
+        pub(crate) const fn new(value: T) -> CmRefCell<T> {
+            CmRefCell(RefCell::new(value))
+        }
+
+        #[inline]
+        #[track_caller]
+        pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> {
+            self.0.borrow_mut()
+        }
+
+        #[inline]
+        #[track_caller]
+        pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> {
+            if r.assert_speculative {
+                panic!("Not allowed to mutably borrow a CmRefCell during speculative resolution");
+            }
+            self.borrow_mut_unchecked()
+        }
+
+        #[inline]
+        #[track_caller]
+        pub(crate) fn try_borrow_mut_unchecked(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
+            self.0.try_borrow_mut()
+        }
+
+        #[inline]
+        #[track_caller]
+        pub(crate) fn borrow(&self) -> Ref<'_, T> {
+            self.0.borrow()
+        }
+    }
+}
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d3e98ef839b..c50dfd41b51 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -189,7 +189,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
         let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope);
         self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
 
-        parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
+        parent_scope.module.unexpanded_invocations.borrow_mut(self).remove(&expansion);
         if let Some(unexpanded_invocations) =
             self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion))
         {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 795cb2b2cfe..ebb6a93b1dd 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -29,7 +29,8 @@ use rustc_span::{
     SourceFileHashAlgorithm, Symbol, sym,
 };
 use rustc_target::spec::{
-    FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple,
+    FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo,
+    Target, TargetTuple,
 };
 use tracing::debug;
 
@@ -1620,6 +1621,7 @@ pub struct PacRet {
 pub struct BranchProtection {
     pub bti: bool,
     pub pac_ret: Option<PacRet>,
+    pub gcs: bool,
 }
 
 pub(crate) const fn default_lib_output() -> CrateType {
@@ -2799,6 +2801,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         }
     }
 
+    if !unstable_options_enabled && cg.panic == Some(PanicStrategy::ImmediateAbort) {
+        early_dcx.early_fatal(
+            "`-Cpanic=immediate-abort` requires `-Zunstable-options` and a nightly compiler",
+        )
+    }
+
     let crate_name = matches.opt_str("crate-name");
     let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
     // Parse any `-l` flags, which link to native libraries.
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index 7e970461ab7..f3d91ce4a5d 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -125,7 +125,9 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
                 None | Some(_),
             ) => disallow(cfg, "-Z sanitizer=cfi"),
             (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"),
-            (sym::panic, Some(sym::abort | sym::unwind)) => disallow(cfg, "-C panic"),
+            (sym::panic, Some(sym::abort | sym::unwind | sym::immediate_abort)) => {
+                disallow(cfg, "-C panic")
+            }
             (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"),
             (sym::unix, None)
             | (sym::windows, None)
@@ -203,7 +205,14 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
         ins_none!(sym::overflow_checks);
     }
 
+    // We insert a cfg for the name of session's panic strategy.
+    // Since the ImmediateAbort strategy is new, it also sets cfg(panic="abort"), so that code
+    // which is trying to detect whether unwinding is enabled by checking for cfg(panic="abort")
+    // does not need to be updated.
     ins_sym!(sym::panic, sess.panic_strategy().desc_symbol());
+    if sess.panic_strategy() == PanicStrategy::ImmediateAbort {
+        ins_sym!(sym::panic, PanicStrategy::Abort.desc_symbol());
+    }
 
     // JUSTIFICATION: before wrapper fn is available
     #[allow(rustc::bad_opt_access)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 69facde6936..b2cc169f12c 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -802,7 +802,7 @@ mod desc {
     pub(crate) const parse_threads: &str = parse_number;
     pub(crate) const parse_time_passes_format: &str = "`text` (default) or `json`";
     pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`";
-    pub(crate) const parse_panic_strategy: &str = "either `unwind` or `abort`";
+    pub(crate) const parse_panic_strategy: &str = "either `unwind`, `abort`, or `immediate-abort`";
     pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
     pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)";
     pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy;
@@ -866,7 +866,7 @@ mod desc {
     pub(crate) const parse_polonius: &str = "either no value or `legacy` (the default), or `next`";
     pub(crate) const parse_stack_protector: &str =
         "one of (`none` (default), `basic`, `strong`, or `all`)";
-    pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf`";
+    pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)";
     pub(crate) const parse_proc_macro_execution_strategy: &str =
         "one of supported execution strategies (`same-thread`, or `cross-thread`)";
     pub(crate) const parse_remap_path_scope: &str =
@@ -1165,6 +1165,7 @@ pub mod parse {
         match v {
             Some("unwind") => *slot = Some(PanicStrategy::Unwind),
             Some("abort") => *slot = Some(PanicStrategy::Abort),
+            Some("immediate-abort") => *slot = Some(PanicStrategy::ImmediateAbort),
             _ => return false,
         }
         true
@@ -1174,6 +1175,7 @@ pub mod parse {
         match v {
             Some("unwind") => *slot = PanicStrategy::Unwind,
             Some("abort") => *slot = PanicStrategy::Abort,
+            Some("immediate-abort") => *slot = PanicStrategy::ImmediateAbort,
             _ => return false,
         }
         true
@@ -1903,6 +1905,7 @@ pub mod parse {
                             Some(pac) => pac.pc = true,
                             _ => return false,
                         },
+                        "gcs" => slot.gcs = true,
                         _ => return false,
                     };
                 }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index d0dd2cdac0c..25b46241c52 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -777,9 +777,11 @@ impl Session {
         // Otherwise, we can defer to the `-C force-unwind-tables=<yes/no>`
         // value, if it is provided, or disable them, if not.
         self.target.requires_uwtable
-            || self.opts.cg.force_unwind_tables.unwrap_or(
-                self.panic_strategy() == PanicStrategy::Unwind || self.target.default_uwtable,
-            )
+            || self
+                .opts
+                .cg
+                .force_unwind_tables
+                .unwrap_or(self.panic_strategy().unwinds() || self.target.default_uwtable)
     }
 
     /// Returns the number of query threads that should be used for this
@@ -1229,7 +1231,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     }
 
     // KCFI requires panic=abort
-    if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy() != PanicStrategy::Abort {
+    if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy().unwinds() {
         sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort);
     }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 4fef65f46b1..faf32523baa 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -794,6 +794,7 @@ symbols! {
         ctlz,
         ctlz_nonzero,
         ctpop,
+        ctr,
         cttz,
         cttz_nonzero,
         custom_attribute,
@@ -1195,6 +1196,7 @@ symbols! {
         if_let_rescope,
         if_while_or_patterns,
         ignore,
+        immediate_abort: "immediate-abort",
         impl_header_lifetime_elision,
         impl_lint_pass,
         impl_trait_in_assoc_type,
@@ -1333,6 +1335,7 @@ symbols! {
         loongarch_target_feature,
         loop_break_value,
         loop_match,
+        lr,
         lt,
         m68k_target_feature,
         macro_at_most_once_rep,
@@ -1940,6 +1943,7 @@ symbols! {
         rustc_regions,
         rustc_reservation_impl,
         rustc_serialize,
+        rustc_simd_monomorphize_lane_limit,
         rustc_skip_during_method_dispatch,
         rustc_specialization_trait,
         rustc_std_internal_symbol,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 9fa7e2f1003..d24924b424a 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -262,15 +262,16 @@ impl<'tcx> V0SymbolMangler<'tcx> {
     fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> {
         Ok(match *pat {
             ty::PatternKind::Range { start, end } => {
-                let consts = [start, end];
-                for ct in consts {
-                    Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
-                }
+                self.push("R");
+                self.print_const(start)?;
+                self.print_const(end)?;
             }
             ty::PatternKind::Or(patterns) => {
+                self.push("O");
                 for pat in patterns {
                     self.print_pat(pat)?;
                 }
+                self.push("E");
             }
         })
     }
@@ -498,12 +499,9 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
             }
 
             ty::Pat(ty, pat) => {
-                // HACK: Represent as tuple until we have something better.
-                // HACK: constants are used in arrays, even if the types don't match.
-                self.push("T");
+                self.push("W");
                 ty.print(self)?;
                 self.print_pat(pat)?;
-                self.push("E");
             }
 
             ty::Array(ty, len) => {
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index e06f881e4b1..0601613567e 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -1260,11 +1260,12 @@ impl InlineAsmClobberAbi {
                     v8, v9, v10, v11, v12, v13, v14,
                     v15, v16, v17, v18, v19,
 
-                    // cr0-cr1, cr5-cr7, xer
+                    // cr0-cr1, cr5-cr7, ctr, lr, xer
                     cr0, cr1,
                     cr5, cr6, cr7,
+                    ctr,
+                    lr,
                     xer,
-                    // lr and ctr are reserved
                 }
             },
             InlineAsmClobberAbi::S390x => clobbered_regs! {
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index f3934afa6d9..2348a0fd202 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -13,6 +13,8 @@ def_reg_class! {
         freg,
         vreg,
         cr,
+        ctr,
+        lr,
         xer,
     }
 }
@@ -56,7 +58,7 @@ impl PowerPCInlineAsmRegClass {
                 altivec: VecI8(16), VecI16(8), VecI32(4), VecF32(4);
                 vsx: F32, F64, VecI64(2), VecF64(2);
             },
-            Self::cr | Self::xer => &[],
+            Self::cr | Self::ctr | Self::lr | Self::xer => &[],
         }
     }
 }
@@ -195,6 +197,8 @@ def_regs! {
         cr5: cr = ["cr5"],
         cr6: cr = ["cr6"],
         cr7: cr = ["cr7"],
+        ctr: ctr = ["ctr"],
+        lr: lr = ["lr"],
         xer: xer = ["xer"],
         #error = ["r1", "1", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
@@ -206,10 +210,6 @@ def_regs! {
             "r30 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r31", "31", "fp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
-        #error = ["lr"] =>
-            "the link register cannot be used as an operand for inline asm",
-        #error = ["ctr"] =>
-            "the counter register cannot be used as an operand for inline asm",
         #error = ["vrsave"] =>
             "the vrsave register cannot be used as an operand for inline asm",
     }
@@ -247,6 +247,8 @@ impl PowerPCInlineAsmReg {
             (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31");
             (cr, "cr");
             (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
+            (ctr, "ctr");
+            (lr, "lr");
             (xer, "xer");
         }
     }
diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs
index be15da7329d..6ab8597a4ec 100644
--- a/compiler/rustc_target/src/spec/base/mod.rs
+++ b/compiler/rustc_target/src/spec/base/mod.rs
@@ -21,6 +21,7 @@ pub(crate) mod linux_uclibc;
 pub(crate) mod linux_wasm;
 pub(crate) mod lynxos178;
 pub(crate) mod managarm_mlibc;
+pub(crate) mod motor;
 pub(crate) mod msvc;
 pub(crate) mod netbsd;
 pub(crate) mod nto_qnx;
diff --git a/compiler/rustc_target/src/spec/base/motor.rs b/compiler/rustc_target/src/spec/base/motor.rs
new file mode 100644
index 00000000000..18485b2cef2
--- /dev/null
+++ b/compiler/rustc_target/src/spec/base/motor.rs
@@ -0,0 +1,34 @@
+use crate::spec::{
+    Cc, FramePointer, LinkerFlavor, Lld, PanicStrategy, StackProbeType, TargetOptions,
+};
+
+pub(crate) fn opts() -> TargetOptions {
+    let pre_link_args = TargetOptions::link_args(
+        LinkerFlavor::Gnu(Cc::No, Lld::No),
+        &[
+            "-e",
+            "motor_start",
+            "--no-undefined",
+            "--error-unresolved-symbols",
+            "--no-undefined-version",
+            "-u",
+            "__rust_abort",
+        ],
+    );
+    TargetOptions {
+        os: "motor".into(),
+        executables: true,
+        // TLS is false below because if true, the compiler assumes
+        // we handle TLS at the ELF loading level, which we don't.
+        // We use "OS level" TLS (see thread/local.rs in stdlib).
+        has_thread_local: false,
+        frame_pointer: FramePointer::NonLeaf,
+        linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No),
+        main_needs_argc_argv: true,
+        panic_strategy: PanicStrategy::Abort,
+        pre_link_args,
+        stack_probes: StackProbeType::Inline,
+        supports_stack_protector: true,
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs
index 88e7af5e669..7ede45766ea 100644
--- a/compiler/rustc_target/src/spec/base/wasm.rs
+++ b/compiler/rustc_target/src/spec/base/wasm.rs
@@ -81,11 +81,6 @@ pub(crate) fn options() -> TargetOptions {
         // threaded model which will legalize atomics to normal operations.
         singlethread: true,
 
-        // Symbol visibility takes care of this for the WebAssembly.
-        // Additionally the only known linker, LLD, doesn't support the script
-        // arguments just yet
-        limit_rdylib_exports: false,
-
         // we use the LLD shipped with the Rust toolchain by default
         linker: Some("rust-lld".into()),
         linker_flavor: LinkerFlavor::WasmLld(Cc::No),
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index 4ba11021988..2867428e42f 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -93,10 +93,7 @@ pub(crate) fn opts() -> TargetOptions {
         binary_format: BinaryFormat::Coff,
         allows_weak_linkage: false,
         pre_link_args,
-        pre_link_objects: crt_objects::pre_mingw(),
-        post_link_objects: crt_objects::post_mingw(),
         pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(),
-        post_link_objects_self_contained: crt_objects::post_mingw_self_contained(),
         link_self_contained: LinkSelfContainedDefault::InferredForMingw,
         late_link_args,
         late_link_args_dynamic,
diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index e3b6430a463..2d84e78f255 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -86,6 +86,17 @@ pub(super) fn post_musl_self_contained() -> CrtObjects {
 
 pub(super) fn pre_mingw_self_contained() -> CrtObjects {
     new(&[
+        (LinkOutputKind::DynamicNoPicExe, &["crt2.o"]),
+        (LinkOutputKind::DynamicPicExe, &["crt2.o"]),
+        (LinkOutputKind::StaticNoPicExe, &["crt2.o"]),
+        (LinkOutputKind::StaticPicExe, &["crt2.o"]),
+        (LinkOutputKind::DynamicDylib, &["dllcrt2.o"]),
+        (LinkOutputKind::StaticDylib, &["dllcrt2.o"]),
+    ])
+}
+
+pub(super) fn pre_i686_mingw_self_contained() -> CrtObjects {
+    new(&[
         (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
         (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
         (LinkOutputKind::StaticNoPicExe, &["crt2.o", "rsbegin.o"]),
@@ -95,15 +106,15 @@ pub(super) fn pre_mingw_self_contained() -> CrtObjects {
     ])
 }
 
-pub(super) fn post_mingw_self_contained() -> CrtObjects {
+pub(super) fn post_i686_mingw_self_contained() -> CrtObjects {
     all("rsend.o")
 }
 
-pub(super) fn pre_mingw() -> CrtObjects {
+pub(super) fn pre_i686_mingw() -> CrtObjects {
     all("rsbegin.o")
 }
 
-pub(super) fn post_mingw() -> CrtObjects {
+pub(super) fn post_i686_mingw() -> CrtObjects {
     all("rsend.o")
 }
 
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f705af52bd8..4a82a8bd888 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -834,6 +834,7 @@ crate::target_spec_enum! {
     pub enum PanicStrategy {
         Unwind = "unwind",
         Abort = "abort",
+        ImmediateAbort = "immediate-abort",
     }
 
     parse_error_type = "panic strategy";
@@ -852,8 +853,13 @@ impl PanicStrategy {
         match *self {
             PanicStrategy::Unwind => sym::unwind,
             PanicStrategy::Abort => sym::abort,
+            PanicStrategy::ImmediateAbort => sym::immediate_abort,
         }
     }
+
+    pub fn unwinds(self) -> bool {
+        matches!(self, PanicStrategy::Unwind)
+    }
 }
 
 crate::target_spec_enum! {
@@ -1642,6 +1648,7 @@ supported_targets! {
     ("aarch64-unknown-hermit", aarch64_unknown_hermit),
     ("riscv64gc-unknown-hermit", riscv64gc_unknown_hermit),
     ("x86_64-unknown-hermit", x86_64_unknown_hermit),
+    ("x86_64-unknown-motor", x86_64_unknown_motor),
 
     ("x86_64-unikraft-linux-musl", x86_64_unikraft_linux_musl),
 
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
index d227d63c4a3..0ae7cd7a377 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabi.rs
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
         llvm_target: "armebv7r-none-eabi".into(),
         metadata: TargetMetadata {
             description: Some("Bare Armv7-R, Big Endian".into()),
-            tier: Some(2),
+            tier: Some(3),
             host_tools: Some(false),
             std: Some(false),
         },
diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
index c373afb914e..71ffd8baed5 100644
--- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs
@@ -12,7 +12,7 @@ pub(crate) fn target() -> Target {
         llvm_target: "armebv7r-none-eabihf".into(),
         metadata: TargetMetadata {
             description: Some("Bare Armv7-R, Big Endian, hardfloat".into()),
-            tier: Some(2),
+            tier: Some(3),
             host_tools: Some(false),
             std: Some(false),
         },
diff --git a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs
index e78f7839974..06dd2629775 100644
--- a/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7a_vex_v5.rs
@@ -34,7 +34,7 @@ pub(crate) fn target() -> Target {
             description: Some("ARMv7-A Cortex-A9 VEX V5 Brain".into()),
             tier: Some(3),
             host_tools: Some(false),
-            std: Some(false),
+            std: Some(true),
         },
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
index e775c8fc524..a0d403bd05e 100644
--- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs
@@ -1,4 +1,6 @@
-use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base};
+use crate::spec::{
+    Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base, crt_objects,
+};
 
 pub(crate) fn target() -> Target {
     let mut base = base::windows_gnu::opts();
@@ -15,6 +17,10 @@ pub(crate) fn target() -> Target {
         &["-m", "i386pe", "--large-address-aware"],
     );
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,--large-address-aware"]);
+    base.pre_link_objects = crt_objects::pre_i686_mingw();
+    base.post_link_objects = crt_objects::post_i686_mingw();
+    base.pre_link_objects_self_contained = crt_objects::pre_i686_mingw_self_contained();
+    base.post_link_objects_self_contained = crt_objects::post_i686_mingw_self_contained();
 
     Target {
         llvm_target: "i686-pc-windows-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
index d42e097b0fd..38c3c7dfaa1 100644
--- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
@@ -5,8 +5,6 @@ pub(crate) fn target() -> Target {
     base.cpu = "mips64r2".into();
     base.features = "+mips64r2,+xgot".into();
     base.max_atomic_width = Some(64);
-    // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
-    base.crt_static_default = true;
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64el-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs
new file mode 100644
index 00000000000..0fd43357a76
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_motor.rs
@@ -0,0 +1,38 @@
+use crate::spec::{
+    CodeModel, LinkSelfContainedDefault, LldFlavor, RelocModel, RelroLevel, Target, base,
+};
+
+pub(crate) fn target() -> Target {
+    let mut base = base::motor::opts();
+    base.cpu = "x86-64".into();
+    base.max_atomic_width = Some(64);
+    base.code_model = Some(CodeModel::Small);
+
+    // We want fully static relocatable binaries. It was surprisingly
+    // difficult to make it happen reliably, especially various
+    // linker-related options below. Mostly trial and error.
+    base.position_independent_executables = true;
+    base.relro_level = RelroLevel::Full;
+    base.static_position_independent_executables = true;
+    base.relocation_model = RelocModel::Pic;
+    base.lld_flavor_json = LldFlavor::Ld;
+    base.link_self_contained = LinkSelfContainedDefault::True;
+    base.dynamic_linking = false;
+    base.crt_static_default = true;
+    base.crt_static_respected = true;
+
+    Target {
+        llvm_target: "x86_64-unknown-none-elf".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("Motor OS".into()),
+            tier: Some(3),
+            host_tools: None,
+            std: None,
+        },
+        pointer_width: 64,
+        data_layout:
+            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+        arch: "x86_64".into(),
+        options: base,
+    }
+}
diff --git a/compiler/rustc_thread_pool/src/latch.rs b/compiler/rustc_thread_pool/src/latch.rs
index 18d654d9f78..58dabaf35c0 100644
--- a/compiler/rustc_thread_pool/src/latch.rs
+++ b/compiler/rustc_thread_pool/src/latch.rs
@@ -388,13 +388,17 @@ impl Latch for CountLatch {
     #[inline]
     unsafe fn set(this: *const Self) {
         if unsafe { (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 } {
-            // NOTE: Once we call `set` on the internal `latch`,
+            // SAFETY: Once we call `set` on the internal `latch`,
             // the target may proceed and invalidate `this`!
             match unsafe { &(*this).kind } {
                 CountLatchKind::Stealing { latch, registry, worker_index } => {
                     let registry = Arc::clone(registry);
+                    let worker_index = *worker_index;
+                    // SAFETY: We don't use any references from `this` after this call.
                     if unsafe { CoreLatch::set(latch) } {
-                        registry.notify_worker_latch_is_set(*worker_index);
+                        // We **must not** access any part of `this` anymore, which
+                        // is why we read and shadowed these fields beforehand.
+                        registry.notify_worker_latch_is_set(worker_index);
                     }
                 }
                 CountLatchKind::Blocking { latch } => unsafe { LockLatch::set(latch) },
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 149f5e638b1..d485eb7266b 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
@@ -1305,8 +1305,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 {
                     if ty.is_structural_eq_shallow(self.tcx) {
                         diag.span_suggestion(
-                            span,
-                            "add `#[derive(ConstParamTy)]` to the struct",
+                            span.shrink_to_lo(),
+                            format!("add `#[derive(ConstParamTy)]` to the {}", def.descr()),
                             "#[derive(ConstParamTy)]\n",
                             Applicability::MachineApplicable,
                         );
@@ -1314,8 +1314,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         // FIXME(adt_const_params): We should check there's not already an
                         // overlapping `Eq`/`PartialEq` impl.
                         diag.span_suggestion(
-                            span,
-                            "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct",
+                            span.shrink_to_lo(),
+                            format!(
+                                "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the {}",
+                                def.descr()
+                            ),
                             "#[derive(ConstParamTy, PartialEq, Eq)]\n",
                             Applicability::MachineApplicable,
                         );
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 4c50c44b841..cd076d1cb69 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -9,7 +9,7 @@ use rustc_middle::infer::canonical::{
     Canonical, CanonicalQueryInput, CanonicalQueryResponse, QueryResponse,
 };
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast};
+use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, Upcast};
 use rustc_span::DUMMY_SP;
 use tracing::instrument;
 
@@ -31,19 +31,7 @@ impl<'tcx> InferCtxt<'tcx> {
 
     fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let ty = self.resolve_vars_if_possible(ty);
-
-        // FIXME(#132279): This should be removed as it causes us to incorrectly
-        // handle opaques in their defining scope, and stalled coroutines.
-        if !self.next_trait_solver() && !(param_env, ty).has_infer() && !ty.has_coroutines() {
-            return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty);
-        }
-
         let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP);
-
-        // This can get called from typeck (by euv), and `moves_by_default`
-        // rightly refuses to work with inference variables, but
-        // moves_by_default has a cache, which we want to use in other
-        // cases.
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 6ce68507d65..a96cb738b81 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -100,9 +100,9 @@ where
         } else if let Err(guar) = infcx.tcx.check_potentially_region_dependent_goals(root_def_id) {
             Err(guar)
         } else {
-            Err(infcx
-                .dcx()
-                .delayed_bug(format!("errors selecting obligation during MIR typeck: {errors:?}")))
+            Err(infcx.dcx().delayed_bug(format!(
+                "errors selecting obligation during MIR typeck: {name} {root_def_id:?} {errors:?}"
+            )))
         }
     })?;
 
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index d7ea26a2ab1..a02e8ecf613 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -279,6 +279,7 @@ pub(crate) mod rustc {
                 LayoutError::Unknown(..)
                 | LayoutError::ReferencesError(..)
                 | LayoutError::TooGeneric(..)
+                | LayoutError::InvalidSimd { .. }
                 | LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
                 LayoutError::SizeOverflow(..) => Self::SizeOverflow,
                 LayoutError::Cycle(err) => Self::TypeError(*err),
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 0298e7e0e95..f92c405242c 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -79,19 +79,6 @@ pub(crate) struct UnexpectedFnPtrAssociatedItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(ty_utils_zero_length_simd_type)]
-pub(crate) struct ZeroLengthSimdType<'tcx> {
-    pub ty: Ty<'tcx>,
-}
-
-#[derive(Diagnostic)]
-#[diag(ty_utils_oversized_simd_type)]
-pub(crate) struct OversizedSimdType<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub max_lanes: u64,
-}
-
-#[derive(Diagnostic)]
 #[diag(ty_utils_non_primitive_simd_type)]
 pub(crate) struct NonPrimitiveSimdType<'tcx> {
     pub ty: Ty<'tcx>,
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index c4cb43011ad..f59bc2117d5 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -7,12 +7,14 @@ use rustc_abi::{
     VariantIdx, Variants, WrappingRange,
 };
 use rustc_hashes::Hash64;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::find_attr;
 use rustc_index::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::layout::{
-    FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
+    FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
@@ -23,7 +25,7 @@ use rustc_span::{Symbol, sym};
 use tracing::{debug, instrument};
 use {rustc_abi as abi, rustc_hir as hir};
 
-use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType};
+use crate::errors::NonPrimitiveSimdType;
 
 mod invariant;
 
@@ -121,11 +123,11 @@ fn map_error<'tcx>(
         }
         LayoutCalculatorError::ZeroLengthSimdType => {
             // Can't be caught in typeck if the array length is generic.
-            cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty })
+            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength }
         }
         LayoutCalculatorError::OversizedSimdType { max_lanes } => {
             // Can't be caught in typeck if the array length is generic.
-            cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes })
+            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) }
         }
         LayoutCalculatorError::NonPrimitiveSimdType(field) => {
             // This error isn't caught in typeck, e.g., if
@@ -563,6 +565,22 @@ fn layout_of_uncached<'tcx>(
 
             let e_ly = cx.layout_of(e_ty)?;
 
+            // Check for the rustc_simd_monomorphize_lane_limit attribute and check the lane limit
+            if let Some(limit) = find_attr!(
+                tcx.get_all_attrs(def.did()),
+                AttributeKind::RustcSimdMonomorphizeLaneLimit(limit) => limit
+            ) {
+                if !limit.value_within_limit(e_len as usize) {
+                    return Err(map_error(
+                        &cx,
+                        ty,
+                        rustc_abi::LayoutCalculatorError::OversizedSimdType {
+                            max_lanes: limit.0 as u64,
+                        },
+                    ));
+                }
+            }
+
             map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
         }
 
diff --git a/compiler/rustc_windows_rc/Cargo.toml b/compiler/rustc_windows_rc/Cargo.toml
index 080acd35c38..13f716897fa 100644
--- a/compiler/rustc_windows_rc/Cargo.toml
+++ b/compiler/rustc_windows_rc/Cargo.toml
@@ -5,7 +5,5 @@ edition = "2024"
 
 [dependencies]
 #tidy-alphabetical-start
-# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
-# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_codegen_ssa`.
-cc = "=1.2.16"
+find-msvc-tools = "0.1.2"
 #tidy-alphabetical-end
diff --git a/compiler/rustc_windows_rc/src/lib.rs b/compiler/rustc_windows_rc/src/lib.rs
index 5e95557501e..15afaf7b94b 100644
--- a/compiler/rustc_windows_rc/src/lib.rs
+++ b/compiler/rustc_windows_rc/src/lib.rs
@@ -2,9 +2,7 @@
 //!
 //! Uses values from the `CFG_VERSION` and `CFG_RELEASE` environment variables
 //! to set the product and file version information in the Windows resource file.
-use std::{env, ffi, fs, path, process};
-
-use cc::windows_registry;
+use std::{env, fs, path, process};
 
 /// The template for the Windows resource file.
 const RESOURCE_TEMPLATE: &str = include_str!("../rustc.rc.in");
@@ -38,7 +36,10 @@ pub fn compile_windows_resource_file(
     let resource_compiler = if let Ok(path) = env::var("RUSTC_WINDOWS_RC") {
         path.into()
     } else {
-        find_resource_compiler(&env::var("CARGO_CFG_TARGET_ARCH").unwrap()).expect("found rc.exe")
+        find_msvc_tools::find_tool(&env::var("CARGO_CFG_TARGET_ARCH").unwrap(), "rc.exe")
+            .expect("found rc.exe")
+            .path()
+            .to_owned()
     };
 
     let rc_path = resources_dir.join(file_stem.with_extension("rc"));
@@ -134,28 +135,3 @@ fn parse_version(version: &str) -> Option<ResourceVersion> {
         Some(ResourceVersion { major, minor, patch, build: 0 })
     }
 }
-
-/// Find the Windows SDK resource compiler `rc.exe` for the given architecture or target triple.
-/// Returns `None` if the tool could not be found.
-fn find_resource_compiler(arch_or_target: &str) -> Option<path::PathBuf> {
-    find_windows_sdk_tool(arch_or_target, "rc.exe")
-}
-
-/// Find a Windows SDK tool for the given architecture or target triple.
-/// Returns `None` if the tool could not be found.
-fn find_windows_sdk_tool(arch_or_target: &str, tool_name: &str) -> Option<path::PathBuf> {
-    // windows_registry::find_tool can only find MSVC tools, not Windows SDK tools, but
-    // cc does include the Windows SDK tools in the PATH environment of MSVC tools.
-
-    let msvc_linker = windows_registry::find_tool(arch_or_target, "link.exe")?;
-    let path = &msvc_linker.env().iter().find(|(k, _)| k == "PATH")?.1;
-    find_tool_in_path(tool_name, path)
-}
-
-/// Find a tool in the directories in a given PATH-like string.
-fn find_tool_in_path<P: AsRef<ffi::OsStr>>(tool_name: &str, path: P) -> Option<path::PathBuf> {
-    env::split_paths(path.as_ref()).find_map(|p| {
-        let tool_path = p.join(tool_name);
-        if tool_path.try_exists().unwrap_or(false) { Some(tool_path) } else { None }
-    })
-}
diff --git a/library/Cargo.lock b/library/Cargo.lock
index e4b3839847b..47fbf5169f4 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -326,6 +326,7 @@ dependencies = [
  "rustc-demangle",
  "std_detect",
  "unwind",
+ "vex-sdk",
  "wasi 0.11.1+wasi-snapshot-preview1",
  "wasi 0.14.4+wasi-0.2.4",
  "windows-targets 0.0.0",
@@ -380,6 +381,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "vex-sdk"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89f74fce61d7a7ba1589da9634c6305a72befb7cc9150c1f872d87d8060f32b9"
+dependencies = [
+ "rustc-std-workspace-core",
+]
+
+[[package]]
 name = "wasi"
 version = "0.11.1+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 9ba7c5bd28a..fb1f8c86dbf 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -22,8 +22,6 @@ compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features
 compiler-builtins-mem = ['compiler_builtins/mem']
 compiler-builtins-c = ["compiler_builtins/c"]
 compiler-builtins-no-f16-f128 = ["compiler_builtins/no-f16-f128"]
-# Make panics and failed asserts immediately abort without formatting any message
-panic_immediate_abort = ["core/panic_immediate_abort"]
 # Choose algorithms that are optimized for binary size instead of runtime performance
 optimize_for_size = ["core/optimize_for_size"]
 
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 76630a746dd..65c8206e9d4 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -408,12 +408,12 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
         }
     }
 
-    #[cfg(not(feature = "panic_immediate_abort"))]
+    #[cfg(not(panic = "immediate-abort"))]
     {
         core::intrinsics::const_eval_select((layout,), ct_error, rt_error)
     }
 
-    #[cfg(feature = "panic_immediate_abort")]
+    #[cfg(panic = "immediate-abort")]
     ct_error(layout)
 }
 
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index cebd25c6039..e3b53b2fe29 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -194,6 +194,9 @@ pub struct BTreeMap<
     root: Option<Root<K, V>>,
     length: usize,
     /// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
+    // Although some of the accessory types store a copy of the allocator, the nodes do not.
+    // Because allocations will remain live as long as any copy (like this one) of the allocator
+    // is live, it's unnecessary to store the allocator in each node.
     pub(super) alloc: ManuallyDrop<A>,
     // For dropck; the `Box` avoids making the `Unpin` impl more strict than before
     _marker: PhantomData<crate::boxed::Box<(K, V), A>>,
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index b233e1740b7..a87259e7c58 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -117,10 +117,11 @@ impl<K, V> InternalNode<K, V> {
     /// initialized and valid edge. This function does not set up
     /// such an edge.
     unsafe fn new<A: Allocator + Clone>(alloc: A) -> Box<Self, A> {
+        let mut node = Box::<Self, _>::new_uninit_in(alloc);
         unsafe {
-            let mut node = Box::<Self, _>::new_uninit_in(alloc);
-            // We only need to initialize the data; the edges are MaybeUninit.
+            // SAFETY: argument points to the `node.data` `LeafNode`
             LeafNode::init(&raw mut (*node.as_mut_ptr()).data);
+            // SAFETY: `node.data` was just initialized and `node.edges` is MaybeUninit.
             node.assume_init()
         }
     }
@@ -224,7 +225,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
     }
 
     fn from_new_leaf<A: Allocator + Clone>(leaf: Box<LeafNode<K, V>, A>) -> Self {
-        NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
+        // The allocator must be dropped, not leaked.  See also `BTreeMap::alloc`.
+        let (leaf, _alloc) = Box::into_raw_with_allocator(leaf);
+        // SAFETY: the node was just allocated.
+        let node = unsafe { NonNull::new_unchecked(leaf) };
+        NodeRef { height: 0, node, _marker: PhantomData }
     }
 }
 
@@ -242,7 +247,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
         height: usize,
     ) -> Self {
         debug_assert!(height > 0);
-        let node = NonNull::from(Box::leak(internal)).cast();
+        // The allocator must be dropped, not leaked.  See also `BTreeMap::alloc`.
+        let (internal, _alloc) = Box::into_raw_with_allocator(internal);
+        // SAFETY: the node was just allocated.
+        let internal = unsafe { NonNull::new_unchecked(internal) };
+        let node = internal.cast();
         let mut this = NodeRef { height, node, _marker: PhantomData };
         this.borrow_mut().correct_all_childrens_parent_links();
         this
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index b0c8c4b1ca4..3e78d680ea6 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -970,17 +970,14 @@ impl Default for Rc<CStr> {
     /// This may or may not share an allocation with other Rcs on the same thread.
     #[inline]
     fn default() -> Self {
-        let rc = Rc::<[u8]>::from(*b"\0");
-        // `[u8]` has the same layout as `CStr`, and it is `NUL` terminated.
-        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
+        Rc::from(c"")
     }
 }
 
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<CStr> {
     fn default() -> Box<CStr> {
-        let boxed: Box<[u8]> = Box::from([0]);
-        unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
+        Box::from(c"")
     }
 }
 
diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs
index b0027e964e4..1d4a1f592a9 100644
--- a/library/alloc/src/raw_vec/mod.rs
+++ b/library/alloc/src/raw_vec/mod.rs
@@ -23,7 +23,7 @@ mod tests;
 // ensure that the code generation related to these panics is minimal as there's
 // only one location which panics rather than a bunch throughout the module.
 #[cfg(not(no_global_oom_handling))]
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never))]
 #[track_caller]
 fn capacity_overflow() -> ! {
     panic!("capacity overflow");
@@ -177,6 +177,8 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// the returned `RawVec`.
     #[inline]
     pub(crate) const fn new_in(alloc: A) -> Self {
+        // Check assumption made in `current_memory`
+        const { assert!(T::LAYOUT.size() % T::LAYOUT.align() == 0) };
         Self { inner: RawVecInner::new_in(alloc, Alignment::of::<T>()), _marker: PhantomData }
     }
 
@@ -328,7 +330,8 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[inline]
     #[track_caller]
     pub(crate) fn reserve(&mut self, len: usize, additional: usize) {
-        self.inner.reserve(len, additional, T::LAYOUT)
+        // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
+        unsafe { self.inner.reserve(len, additional, T::LAYOUT) }
     }
 
     /// A specialized version of `self.reserve(len, 1)` which requires the
@@ -337,7 +340,8 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[inline(never)]
     #[track_caller]
     pub(crate) fn grow_one(&mut self) {
-        self.inner.grow_one(T::LAYOUT)
+        // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
+        unsafe { self.inner.grow_one(T::LAYOUT) }
     }
 
     /// The same as `reserve`, but returns on errors instead of panicking or aborting.
@@ -346,7 +350,8 @@ impl<T, A: Allocator> RawVec<T, A> {
         len: usize,
         additional: usize,
     ) -> Result<(), TryReserveError> {
-        self.inner.try_reserve(len, additional, T::LAYOUT)
+        // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
+        unsafe { self.inner.try_reserve(len, additional, T::LAYOUT) }
     }
 
     /// Ensures that the buffer contains at least enough space to hold `len +
@@ -369,7 +374,8 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[track_caller]
     pub(crate) fn reserve_exact(&mut self, len: usize, additional: usize) {
-        self.inner.reserve_exact(len, additional, T::LAYOUT)
+        // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
+        unsafe { self.inner.reserve_exact(len, additional, T::LAYOUT) }
     }
 
     /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
@@ -378,7 +384,8 @@ impl<T, A: Allocator> RawVec<T, A> {
         len: usize,
         additional: usize,
     ) -> Result<(), TryReserveError> {
-        self.inner.try_reserve_exact(len, additional, T::LAYOUT)
+        // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
+        unsafe { self.inner.try_reserve_exact(len, additional, T::LAYOUT) }
     }
 
     /// Shrinks the buffer down to the specified capacity. If the given amount
@@ -395,7 +402,8 @@ impl<T, A: Allocator> RawVec<T, A> {
     #[track_caller]
     #[inline]
     pub(crate) fn shrink_to_fit(&mut self, cap: usize) {
-        self.inner.shrink_to_fit(cap, T::LAYOUT)
+        // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
+        unsafe { self.inner.shrink_to_fit(cap, T::LAYOUT) }
     }
 }
 
@@ -518,8 +526,12 @@ impl<A: Allocator> RawVecInner<A> {
         &self.alloc
     }
 
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
     #[inline]
-    fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull<u8>, Layout)> {
+    unsafe fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull<u8>, Layout)> {
         if elem_layout.size() == 0 || self.cap.as_inner() == 0 {
             None
         } else {
@@ -535,48 +547,67 @@ impl<A: Allocator> RawVecInner<A> {
         }
     }
 
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[track_caller]
-    fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) {
+    unsafe fn reserve(&mut self, len: usize, additional: usize, elem_layout: Layout) {
         // Callers expect this function to be very cheap when there is already sufficient capacity.
         // Therefore, we move all the resizing and error-handling logic from grow_amortized and
         // handle_reserve behind a call, while making sure that this function is likely to be
         // inlined as just a comparison and a call if the comparison fails.
         #[cold]
-        fn do_reserve_and_handle<A: Allocator>(
+        unsafe fn do_reserve_and_handle<A: Allocator>(
             slf: &mut RawVecInner<A>,
             len: usize,
             additional: usize,
             elem_layout: Layout,
         ) {
-            if let Err(err) = slf.grow_amortized(len, additional, elem_layout) {
+            // SAFETY: Precondition passed to caller
+            if let Err(err) = unsafe { slf.grow_amortized(len, additional, elem_layout) } {
                 handle_error(err);
             }
         }
 
         if self.needs_to_grow(len, additional, elem_layout) {
-            do_reserve_and_handle(self, len, additional, elem_layout);
+            unsafe {
+                do_reserve_and_handle(self, len, additional, elem_layout);
+            }
         }
     }
 
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[track_caller]
-    fn grow_one(&mut self, elem_layout: Layout) {
-        if let Err(err) = self.grow_amortized(self.cap.as_inner(), 1, elem_layout) {
+    unsafe fn grow_one(&mut self, elem_layout: Layout) {
+        // SAFETY: Precondition passed to caller
+        if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } {
             handle_error(err);
         }
     }
 
-    fn try_reserve(
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
+    unsafe fn try_reserve(
         &mut self,
         len: usize,
         additional: usize,
         elem_layout: Layout,
     ) -> Result<(), TryReserveError> {
         if self.needs_to_grow(len, additional, elem_layout) {
-            self.grow_amortized(len, additional, elem_layout)?;
+            // SAFETY: Precondition passed to caller
+            unsafe {
+                self.grow_amortized(len, additional, elem_layout)?;
+            }
         }
         unsafe {
             // Inform the optimizer that the reservation has succeeded or wasn't needed
@@ -585,22 +616,34 @@ impl<A: Allocator> RawVecInner<A> {
         Ok(())
     }
 
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
     #[cfg(not(no_global_oom_handling))]
     #[track_caller]
-    fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) {
-        if let Err(err) = self.try_reserve_exact(len, additional, elem_layout) {
+    unsafe fn reserve_exact(&mut self, len: usize, additional: usize, elem_layout: Layout) {
+        // SAFETY: Precondition passed to caller
+        if let Err(err) = unsafe { self.try_reserve_exact(len, additional, elem_layout) } {
             handle_error(err);
         }
     }
 
-    fn try_reserve_exact(
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
+    unsafe fn try_reserve_exact(
         &mut self,
         len: usize,
         additional: usize,
         elem_layout: Layout,
     ) -> Result<(), TryReserveError> {
         if self.needs_to_grow(len, additional, elem_layout) {
-            self.grow_exact(len, additional, elem_layout)?;
+            // SAFETY: Precondition passed to caller
+            unsafe {
+                self.grow_exact(len, additional, elem_layout)?;
+            }
         }
         unsafe {
             // Inform the optimizer that the reservation has succeeded or wasn't needed
@@ -609,11 +652,16 @@ impl<A: Allocator> RawVecInner<A> {
         Ok(())
     }
 
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
+    /// - `cap` must be less than or equal to `self.capacity(elem_layout.size())`
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[track_caller]
-    fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) {
-        if let Err(err) = self.shrink(cap, elem_layout) {
+    unsafe fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) {
+        if let Err(err) = unsafe { self.shrink(cap, elem_layout) } {
             handle_error(err);
         }
     }
@@ -632,7 +680,13 @@ impl<A: Allocator> RawVecInner<A> {
         self.cap = unsafe { Cap::new_unchecked(cap) };
     }
 
-    fn grow_amortized(
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
+    /// - The sum of `len` and `additional` must be greater than or equal to
+    ///   `self.capacity(elem_layout.size())`
+    unsafe fn grow_amortized(
         &mut self,
         len: usize,
         additional: usize,
@@ -657,14 +711,25 @@ impl<A: Allocator> RawVecInner<A> {
 
         let new_layout = layout_array(cap, elem_layout)?;
 
-        let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
-        // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
+        // SAFETY:
+        // - For the `current_memory` call: Precondition passed to caller
+        // - For the `finish_grow` call: Precondition passed to caller
+        //   + `current_memory` does the right thing
+        let ptr =
+            unsafe { finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)? };
 
+        // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
         unsafe { self.set_ptr_and_cap(ptr, cap) };
         Ok(())
     }
 
-    fn grow_exact(
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
+    /// - The sum of `len` and `additional` must be greater than or equal to
+    ///   `self.capacity(elem_layout.size())`
+    unsafe fn grow_exact(
         &mut self,
         len: usize,
         additional: usize,
@@ -679,7 +744,12 @@ impl<A: Allocator> RawVecInner<A> {
         let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
         let new_layout = layout_array(cap, elem_layout)?;
 
-        let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?;
+        // SAFETY:
+        // - For the `current_memory` call: Precondition passed to caller
+        // - For the `finish_grow` call: Precondition passed to caller
+        //   + `current_memory` does the right thing
+        let ptr =
+            unsafe { finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)? };
         // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
         unsafe {
             self.set_ptr_and_cap(ptr, cap);
@@ -687,9 +757,14 @@ impl<A: Allocator> RawVecInner<A> {
         Ok(())
     }
 
+    /// # Safety
+    /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
+    ///   initially construct `self`
+    /// - `elem_layout`'s size must be a multiple of its alignment
+    /// - `cap` must be less than or equal to `self.capacity(elem_layout.size())`
     #[cfg(not(no_global_oom_handling))]
     #[inline]
-    fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> {
+    unsafe fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> {
         assert!(cap <= self.capacity(elem_layout.size()), "Tried to shrink to a larger capacity");
         // SAFETY: Just checked this isn't trying to grow
         unsafe { self.shrink_unchecked(cap, elem_layout) }
@@ -711,8 +786,12 @@ impl<A: Allocator> RawVecInner<A> {
         cap: usize,
         elem_layout: Layout,
     ) -> Result<(), TryReserveError> {
-        let (ptr, layout) =
-            if let Some(mem) = self.current_memory(elem_layout) { mem } else { return Ok(()) };
+        // SAFETY: Precondition passed to caller
+        let (ptr, layout) = if let Some(mem) = unsafe { self.current_memory(elem_layout) } {
+            mem
+        } else {
+            return Ok(());
+        };
 
         // If shrinking to 0, deallocate the buffer. We don't reach this point
         // for the T::IS_ZST case since current_memory() will have returned
@@ -748,7 +827,8 @@ impl<A: Allocator> RawVecInner<A> {
     /// Ideally this function would take `self` by move, but it cannot because it exists to be
     /// called from a `Drop` impl.
     unsafe fn deallocate(&mut self, elem_layout: Layout) {
-        if let Some((ptr, layout)) = self.current_memory(elem_layout) {
+        // SAFETY: Precondition passed to caller
+        if let Some((ptr, layout)) = unsafe { self.current_memory(elem_layout) } {
             unsafe {
                 self.alloc.deallocate(ptr, layout);
             }
@@ -756,10 +836,17 @@ impl<A: Allocator> RawVecInner<A> {
     }
 }
 
+/// # Safety
+/// If `current_memory` matches `Some((ptr, old_layout))`:
+/// - `ptr` must denote a block of memory *currently allocated* via `alloc`
+/// - `old_layout` must *fit* that block of memory
+/// - `new_layout` must have the same alignment as `old_layout`
+/// - `new_layout.size()` must be greater than or equal to `old_layout.size()`
+/// If `current_memory` is `None`, this function is safe.
 // not marked inline(never) since we want optimizers to be able to observe the specifics of this
 // function, see tests/codegen-llvm/vec-reserve-extend.rs.
 #[cold]
-fn finish_grow<A>(
+unsafe fn finish_grow<A>(
     new_layout: Layout,
     current_memory: Option<(NonNull<u8>, Layout)>,
     alloc: &mut A,
diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs
index 700fa922739..15f48c03dc5 100644
--- a/library/alloc/src/raw_vec/tests.rs
+++ b/library/alloc/src/raw_vec/tests.rs
@@ -85,7 +85,7 @@ struct ZST;
 fn zst_sanity<T>(v: &RawVec<T>) {
     assert_eq!(v.capacity(), usize::MAX);
     assert_eq!(v.ptr(), core::ptr::Unique::<T>::dangling().as_ptr());
-    assert_eq!(v.inner.current_memory(T::LAYOUT), None);
+    assert_eq!(unsafe { v.inner.current_memory(T::LAYOUT) }, None);
 }
 
 #[test]
@@ -126,12 +126,12 @@ fn zst() {
     assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err);
     zst_sanity(&v);
 
-    assert_eq!(v.inner.grow_amortized(100, usize::MAX - 100, ZST::LAYOUT), cap_err);
-    assert_eq!(v.inner.grow_amortized(101, usize::MAX - 100, ZST::LAYOUT), cap_err);
+    assert_eq!(unsafe { v.inner.grow_amortized(100, usize::MAX - 100, ZST::LAYOUT) }, cap_err);
+    assert_eq!(unsafe { v.inner.grow_amortized(101, usize::MAX - 100, ZST::LAYOUT) }, cap_err);
     zst_sanity(&v);
 
-    assert_eq!(v.inner.grow_exact(100, usize::MAX - 100, ZST::LAYOUT), cap_err);
-    assert_eq!(v.inner.grow_exact(101, usize::MAX - 100, ZST::LAYOUT), cap_err);
+    assert_eq!(unsafe { v.inner.grow_exact(100, usize::MAX - 100, ZST::LAYOUT) }, cap_err);
+    assert_eq!(unsafe { v.inner.grow_exact(101, usize::MAX - 100, ZST::LAYOUT) }, cap_err);
     zst_sanity(&v);
 }
 
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index fcb466778a3..aed3357afbf 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -480,8 +480,6 @@ impl<T> Rc<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::rc::Rc;
     ///
     /// let mut five = Rc::<u32>::new_uninit();
@@ -572,7 +570,6 @@ impl<T> Rc<T> {
     ///
     /// ```
     /// #![feature(allocator_api)]
-    /// #![feature(get_mut_unchecked)]
     ///
     /// use std::rc::Rc;
     ///
@@ -1014,8 +1011,6 @@ impl<T> Rc<[T]> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::rc::Rc;
     ///
     /// let mut values = Rc::<[u32]>::new_uninit_slice(3);
@@ -1181,8 +1176,6 @@ impl<T, A: Allocator> Rc<mem::MaybeUninit<T>, A> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::rc::Rc;
     ///
     /// let mut five = Rc::<u32>::new_uninit();
@@ -1218,8 +1211,6 @@ impl<T, A: Allocator> Rc<[mem::MaybeUninit<T>], A> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::rc::Rc;
     ///
     /// let mut values = Rc::<[u32]>::new_uninit_slice(3);
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 32396cccb8f..a466b74944c 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -480,8 +480,6 @@ impl<T> Arc<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::sync::Arc;
     ///
     /// let mut five = Arc::<u32>::new_uninit();
@@ -586,7 +584,6 @@ impl<T> Arc<T> {
     ///
     /// ```
     /// #![feature(allocator_api)]
-    /// #![feature(get_mut_unchecked)]
     ///
     /// use std::sync::Arc;
     ///
@@ -1156,8 +1153,6 @@ impl<T> Arc<[T]> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::sync::Arc;
     ///
     /// let mut values = Arc::<[u32]>::new_uninit_slice(3);
@@ -1326,8 +1321,6 @@ impl<T, A: Allocator> Arc<mem::MaybeUninit<T>, A> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::sync::Arc;
     ///
     /// let mut five = Arc::<u32>::new_uninit();
@@ -1364,8 +1357,6 @@ impl<T, A: Allocator> Arc<[mem::MaybeUninit<T>], A> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(get_mut_unchecked)]
-    ///
     /// use std::sync::Arc;
     ///
     /// let mut values = Arc::<[u32]>::new_uninit_slice(3);
diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs
index a456d3d9e60..cb9e14f554d 100644
--- a/library/alloc/src/vec/extract_if.rs
+++ b/library/alloc/src/vec/extract_if.rs
@@ -64,27 +64,37 @@ where
     type Item = T;
 
     fn next(&mut self) -> Option<T> {
-        unsafe {
-            while self.idx < self.end {
-                let i = self.idx;
-                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
-                let drained = (self.pred)(&mut v[i]);
-                // Update the index *after* the predicate is called. If the index
-                // is updated prior and the predicate panics, the element at this
-                // index would be leaked.
-                self.idx += 1;
-                if drained {
-                    self.del += 1;
-                    return Some(ptr::read(&v[i]));
-                } else if self.del > 0 {
-                    let del = self.del;
-                    let src: *const T = &v[i];
-                    let dst: *mut T = &mut v[i - del];
-                    ptr::copy_nonoverlapping(src, dst, 1);
+        while self.idx < self.end {
+            let i = self.idx;
+            // SAFETY:
+            //  We know that `i < self.end` from the if guard and that `self.end <= self.old_len` from
+            //  the validity of `Self`. Therefore `i` points to an element within `vec`.
+            //
+            //  Additionally, the i-th element is valid because each element is visited at most once
+            //  and it is the first time we access vec[i].
+            //
+            //  Note: we can't use `vec.get_unchecked_mut(i)` here since the precondition for that
+            //  function is that i < vec.len(), but we've set vec's length to zero.
+            let cur = unsafe { &mut *self.vec.as_mut_ptr().add(i) };
+            let drained = (self.pred)(cur);
+            // Update the index *after* the predicate is called. If the index
+            // is updated prior and the predicate panics, the element at this
+            // index would be leaked.
+            self.idx += 1;
+            if drained {
+                self.del += 1;
+                // SAFETY: We never touch this element again after returning it.
+                return Some(unsafe { ptr::read(cur) });
+            } else if self.del > 0 {
+                // SAFETY: `self.del` > 0, so the hole slot must not overlap with current element.
+                // We use copy for move, and never touch this element again.
+                unsafe {
+                    let hole_slot = self.vec.as_mut_ptr().add(i - self.del);
+                    ptr::copy_nonoverlapping(cur, hole_slot, 1);
                 }
             }
-            None
         }
+        None
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
@@ -95,14 +105,18 @@ where
 #[stable(feature = "extract_if", since = "1.87.0")]
 impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
     fn drop(&mut self) {
-        unsafe {
-            if self.idx < self.old_len && self.del > 0 {
-                let ptr = self.vec.as_mut_ptr();
-                let src = ptr.add(self.idx);
-                let dst = src.sub(self.del);
-                let tail_len = self.old_len - self.idx;
-                src.copy_to(dst, tail_len);
+        if self.del > 0 {
+            // SAFETY: Trailing unchecked items must be valid since we never touch them.
+            unsafe {
+                ptr::copy(
+                    self.vec.as_ptr().add(self.idx),
+                    self.vec.as_mut_ptr().add(self.idx - self.del),
+                    self.old_len - self.idx,
+                );
             }
+        }
+        // SAFETY: After filling holes, all items are in contiguous memory.
+        unsafe {
             self.vec.set_len(self.old_len - self.del);
         }
     }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 10c7ee4f6c8..694b7b2df08 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2020,7 +2020,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn swap_remove(&mut self, index: usize) -> T {
         #[cold]
-        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+        #[cfg_attr(not(panic = "immediate-abort"), inline(never))]
         #[track_caller]
         #[optimize(size)]
         fn assert_failed(index: usize, len: usize) -> ! {
@@ -2102,7 +2102,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[must_use = "if you don't need a reference to the value, use `Vec::insert` instead"]
     pub fn insert_mut(&mut self, index: usize, element: T) -> &mut T {
         #[cold]
-        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+        #[cfg_attr(not(panic = "immediate-abort"), inline(never))]
         #[track_caller]
         #[optimize(size)]
         fn assert_failed(index: usize, len: usize) -> ! {
@@ -2166,16 +2166,44 @@ impl<T, A: Allocator> Vec<T, A> {
     #[rustc_confusables("delete", "take")]
     pub fn remove(&mut self, index: usize) -> T {
         #[cold]
-        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+        #[cfg_attr(not(panic = "immediate-abort"), inline(never))]
         #[track_caller]
         #[optimize(size)]
         fn assert_failed(index: usize, len: usize) -> ! {
             panic!("removal index (is {index}) should be < len (is {len})");
         }
 
+        match self.try_remove(index) {
+            Some(elem) => elem,
+            None => assert_failed(index, self.len()),
+        }
+    }
+
+    /// Remove and return the element at position `index` within the vector,
+    /// shifting all elements after it to the left, or [`None`] if it does not
+    /// exist.
+    ///
+    /// Note: Because this shifts over the remaining elements, it has a
+    /// worst-case performance of *O*(*n*). If you'd like to remove
+    /// elements from the beginning of the `Vec`, consider using
+    /// [`VecDeque::pop_front`] instead.
+    ///
+    /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_try_remove)]
+    /// let mut v = vec![1, 2, 3];
+    /// assert_eq!(v.try_remove(0), Some(1));
+    /// assert_eq!(v.try_remove(2), None);
+    /// ```
+    #[unstable(feature = "vec_try_remove", issue = "146954")]
+    #[rustc_confusables("delete", "take", "remove")]
+    pub fn try_remove(&mut self, index: usize) -> Option<T> {
         let len = self.len();
         if index >= len {
-            assert_failed(index, len);
+            return None;
         }
         unsafe {
             // infallible
@@ -2191,7 +2219,7 @@ impl<T, A: Allocator> Vec<T, A> {
                 ptr::copy(ptr.add(1), ptr, len - index - 1);
             }
             self.set_len(len - 1);
-            ret
+            Some(ret)
         }
     }
 
@@ -2955,7 +2983,7 @@ impl<T, A: Allocator> Vec<T, A> {
         A: Clone,
     {
         #[cold]
-        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+        #[cfg_attr(not(panic = "immediate-abort"), inline(never))]
         #[track_caller]
         #[optimize(size)]
         fn assert_failed(at: usize, len: usize) -> ! {
diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs
index 8c3ce156f3c..49fb21ef5f3 100644
--- a/library/alloctests/tests/lib.rs
+++ b/library/alloctests/tests/lib.rs
@@ -41,12 +41,12 @@
 #![feature(unique_rc_arc)]
 #![feature(macro_metavar_expr_concat)]
 #![feature(vec_peek_mut)]
+#![feature(vec_try_remove)]
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 extern crate alloc;
-extern crate test;
 
 use std::hash::{DefaultHasher, Hash, Hasher};
 
diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs
index 33a34daccbf..ea334ab0f14 100644
--- a/library/alloctests/tests/vec.rs
+++ b/library/alloctests/tests/vec.rs
@@ -631,6 +631,21 @@ fn test_swap_remove_empty() {
 }
 
 #[test]
+fn test_try_remove() {
+    let mut vec = vec![1, 2, 3];
+    // We are attempting to remove vec[0] which contains 1
+    assert_eq!(vec.try_remove(0), Some(1));
+    // Now `vec` looks like: [2, 3]
+    // We will now try to remove vec[2] which does not exist
+    // This should return `None`
+    assert_eq!(vec.try_remove(2), None);
+
+    // We will try the same thing with an empty vector
+    let mut v: Vec<u8> = vec![];
+    assert!(v.try_remove(0).is_none());
+}
+
+#[test]
 fn test_move_items() {
     let vec = vec![1, 2, 3];
     let mut vec2 = vec![];
diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs
index fb790e69615..b5ee6413d55 100644
--- a/library/compiler-builtins/libm/src/math/support/float_traits.rs
+++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs
@@ -289,7 +289,7 @@ macro_rules! float_impl {
                 cfg_if! {
                     // fma is not yet available in `core`
                     if #[cfg(intrinsics_enabled)] {
-                        unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) }
+                        core::intrinsics::$fma_intrinsic(self, y, z)
                     } else {
                         super::super::$fma_fn(self, y, z)
                     }
diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml
index 3e34e03a61e..d094172b076 100644
--- a/library/core/Cargo.toml
+++ b/library/core/Cargo.toml
@@ -16,7 +16,7 @@ test = false
 bench = false
 
 [features]
-# Make panics and failed asserts immediately abort without formatting any message
+# Issue a compile error that says to use -Cpanic=immediate-abort
 panic_immediate_abort = []
 # Choose algorithms that are optimized for binary size instead of runtime performance
 optimize_for_size = []
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 178af2c0e3b..d77fafed203 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -515,7 +515,7 @@ impl AsciiChar {
     #[track_caller]
     pub const unsafe fn digit_unchecked(d: u8) -> Self {
         assert_unsafe_precondition!(
-            check_language_ub,
+            check_library_ub,
             "`ascii::Char::digit_unchecked` input cannot exceed 9.",
             (d: u8 = d) => d < 10
         );
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 9b53b75ebee..7d4a66640b1 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -778,7 +778,7 @@ impl Display for BorrowMutError {
 }
 
 // This ensures the panicking code is outlined from `borrow_mut` for `RefCell`.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never))]
 #[track_caller]
 #[cold]
 const fn panic_already_borrowed(err: BorrowMutError) -> ! {
@@ -790,7 +790,7 @@ const fn panic_already_borrowed(err: BorrowMutError) -> ! {
 }
 
 // This ensures the panicking code is outlined from `borrow` for `RefCell`.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never))]
 #[track_caller]
 #[cold]
 const fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
diff --git a/library/core/src/error.rs b/library/core/src/error.rs
index 92b3c83d1bf..9ca91ee009e 100644
--- a/library/core/src/error.rs
+++ b/library/core/src/error.rs
@@ -16,13 +16,19 @@ use crate::fmt::{self, Debug, Display, Formatter};
 /// assert_eq!(err.to_string(), "invalid digit found in string");
 /// ```
 ///
+/// # Error source
+///
 /// Errors may provide cause information. [`Error::source()`] is generally
 /// used when errors cross "abstraction boundaries". If one module must report
 /// an error that is caused by an error from a lower-level module, it can allow
-/// accessing that error via [`Error::source()`]. This makes it possible for the
+/// accessing that error via `Error::source()`. This makes it possible for the
 /// high-level module to provide its own errors while also revealing some of the
 /// implementation for debugging.
 ///
+/// In error types that wrap an underlying error, the underlying error
+/// should be either returned by the outer error's `Error::source()`, or rendered
+/// by the outer error's `Display` implementation, but not both.
+///
 /// # Example
 ///
 /// Implementing the `Error` trait only requires that `Debug` and `Display` are implemented too.
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index d0b53e3a237..09d9b160700 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -179,9 +179,7 @@ impl fmt::Debug for CStr {
 impl Default for &CStr {
     #[inline]
     fn default() -> Self {
-        const SLICE: &[c_char] = &[0];
-        // SAFETY: `SLICE` is indeed pointing to a valid nul-terminated string.
-        unsafe { CStr::from_ptr(SLICE.as_ptr()) }
+        c""
     }
 }
 
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index bffffbc29c1..cef700be9ea 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -1022,28 +1022,28 @@ pub unsafe fn unaligned_volatile_store<T>(dst: *mut T, val: T);
 /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sqrtf16(x: f16) -> f16;
+pub fn sqrtf16(x: f16) -> f16;
 /// Returns the square root of an `f32`
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sqrtf32(x: f32) -> f32;
+pub fn sqrtf32(x: f32) -> f32;
 /// Returns the square root of an `f64`
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sqrtf64(x: f64) -> f64;
+pub fn sqrtf64(x: f64) -> f64;
 /// Returns the square root of an `f128`
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sqrtf128(x: f128) -> f128;
+pub fn sqrtf128(x: f128) -> f128;
 
 /// Raises an `f16` to an integer power.
 ///
@@ -1051,28 +1051,28 @@ pub unsafe fn sqrtf128(x: f128) -> f128;
 /// [`f16::powi`](../../std/primitive.f16.html#method.powi)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powif16(a: f16, x: i32) -> f16;
+pub fn powif16(a: f16, x: i32) -> f16;
 /// Raises an `f32` to an integer power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::powi`](../../std/primitive.f32.html#method.powi)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powif32(a: f32, x: i32) -> f32;
+pub fn powif32(a: f32, x: i32) -> f32;
 /// Raises an `f64` to an integer power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::powi`](../../std/primitive.f64.html#method.powi)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powif64(a: f64, x: i32) -> f64;
+pub fn powif64(a: f64, x: i32) -> f64;
 /// Raises an `f128` to an integer power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::powi`](../../std/primitive.f128.html#method.powi)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powif128(a: f128, x: i32) -> f128;
+pub fn powif128(a: f128, x: i32) -> f128;
 
 /// Returns the sine of an `f16`.
 ///
@@ -1080,28 +1080,28 @@ pub unsafe fn powif128(a: f128, x: i32) -> f128;
 /// [`f16::sin`](../../std/primitive.f16.html#method.sin)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sinf16(x: f16) -> f16;
+pub fn sinf16(x: f16) -> f16;
 /// Returns the sine of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::sin`](../../std/primitive.f32.html#method.sin)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sinf32(x: f32) -> f32;
+pub fn sinf32(x: f32) -> f32;
 /// Returns the sine of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::sin`](../../std/primitive.f64.html#method.sin)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sinf64(x: f64) -> f64;
+pub fn sinf64(x: f64) -> f64;
 /// Returns the sine of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::sin`](../../std/primitive.f128.html#method.sin)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn sinf128(x: f128) -> f128;
+pub fn sinf128(x: f128) -> f128;
 
 /// Returns the cosine of an `f16`.
 ///
@@ -1109,28 +1109,28 @@ pub unsafe fn sinf128(x: f128) -> f128;
 /// [`f16::cos`](../../std/primitive.f16.html#method.cos)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn cosf16(x: f16) -> f16;
+pub fn cosf16(x: f16) -> f16;
 /// Returns the cosine of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::cos`](../../std/primitive.f32.html#method.cos)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn cosf32(x: f32) -> f32;
+pub fn cosf32(x: f32) -> f32;
 /// Returns the cosine of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::cos`](../../std/primitive.f64.html#method.cos)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn cosf64(x: f64) -> f64;
+pub fn cosf64(x: f64) -> f64;
 /// Returns the cosine of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::cos`](../../std/primitive.f128.html#method.cos)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn cosf128(x: f128) -> f128;
+pub fn cosf128(x: f128) -> f128;
 
 /// Raises an `f16` to an `f16` power.
 ///
@@ -1138,28 +1138,28 @@ pub unsafe fn cosf128(x: f128) -> f128;
 /// [`f16::powf`](../../std/primitive.f16.html#method.powf)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powf16(a: f16, x: f16) -> f16;
+pub fn powf16(a: f16, x: f16) -> f16;
 /// Raises an `f32` to an `f32` power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::powf`](../../std/primitive.f32.html#method.powf)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powf32(a: f32, x: f32) -> f32;
+pub fn powf32(a: f32, x: f32) -> f32;
 /// Raises an `f64` to an `f64` power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::powf`](../../std/primitive.f64.html#method.powf)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powf64(a: f64, x: f64) -> f64;
+pub fn powf64(a: f64, x: f64) -> f64;
 /// Raises an `f128` to an `f128` power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::powf`](../../std/primitive.f128.html#method.powf)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn powf128(a: f128, x: f128) -> f128;
+pub fn powf128(a: f128, x: f128) -> f128;
 
 /// Returns the exponential of an `f16`.
 ///
@@ -1167,28 +1167,28 @@ pub unsafe fn powf128(a: f128, x: f128) -> f128;
 /// [`f16::exp`](../../std/primitive.f16.html#method.exp)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn expf16(x: f16) -> f16;
+pub fn expf16(x: f16) -> f16;
 /// Returns the exponential of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::exp`](../../std/primitive.f32.html#method.exp)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn expf32(x: f32) -> f32;
+pub fn expf32(x: f32) -> f32;
 /// Returns the exponential of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::exp`](../../std/primitive.f64.html#method.exp)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn expf64(x: f64) -> f64;
+pub fn expf64(x: f64) -> f64;
 /// Returns the exponential of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::exp`](../../std/primitive.f128.html#method.exp)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn expf128(x: f128) -> f128;
+pub fn expf128(x: f128) -> f128;
 
 /// Returns 2 raised to the power of an `f16`.
 ///
@@ -1196,28 +1196,28 @@ pub unsafe fn expf128(x: f128) -> f128;
 /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn exp2f16(x: f16) -> f16;
+pub fn exp2f16(x: f16) -> f16;
 /// Returns 2 raised to the power of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn exp2f32(x: f32) -> f32;
+pub fn exp2f32(x: f32) -> f32;
 /// Returns 2 raised to the power of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn exp2f64(x: f64) -> f64;
+pub fn exp2f64(x: f64) -> f64;
 /// Returns 2 raised to the power of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn exp2f128(x: f128) -> f128;
+pub fn exp2f128(x: f128) -> f128;
 
 /// Returns the natural logarithm of an `f16`.
 ///
@@ -1225,28 +1225,28 @@ pub unsafe fn exp2f128(x: f128) -> f128;
 /// [`f16::ln`](../../std/primitive.f16.html#method.ln)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn logf16(x: f16) -> f16;
+pub fn logf16(x: f16) -> f16;
 /// Returns the natural logarithm of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::ln`](../../std/primitive.f32.html#method.ln)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn logf32(x: f32) -> f32;
+pub fn logf32(x: f32) -> f32;
 /// Returns the natural logarithm of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::ln`](../../std/primitive.f64.html#method.ln)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn logf64(x: f64) -> f64;
+pub fn logf64(x: f64) -> f64;
 /// Returns the natural logarithm of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::ln`](../../std/primitive.f128.html#method.ln)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn logf128(x: f128) -> f128;
+pub fn logf128(x: f128) -> f128;
 
 /// Returns the base 10 logarithm of an `f16`.
 ///
@@ -1254,28 +1254,28 @@ pub unsafe fn logf128(x: f128) -> f128;
 /// [`f16::log10`](../../std/primitive.f16.html#method.log10)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log10f16(x: f16) -> f16;
+pub fn log10f16(x: f16) -> f16;
 /// Returns the base 10 logarithm of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::log10`](../../std/primitive.f32.html#method.log10)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log10f32(x: f32) -> f32;
+pub fn log10f32(x: f32) -> f32;
 /// Returns the base 10 logarithm of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::log10`](../../std/primitive.f64.html#method.log10)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log10f64(x: f64) -> f64;
+pub fn log10f64(x: f64) -> f64;
 /// Returns the base 10 logarithm of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::log10`](../../std/primitive.f128.html#method.log10)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log10f128(x: f128) -> f128;
+pub fn log10f128(x: f128) -> f128;
 
 /// Returns the base 2 logarithm of an `f16`.
 ///
@@ -1283,28 +1283,28 @@ pub unsafe fn log10f128(x: f128) -> f128;
 /// [`f16::log2`](../../std/primitive.f16.html#method.log2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log2f16(x: f16) -> f16;
+pub fn log2f16(x: f16) -> f16;
 /// Returns the base 2 logarithm of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::log2`](../../std/primitive.f32.html#method.log2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log2f32(x: f32) -> f32;
+pub fn log2f32(x: f32) -> f32;
 /// Returns the base 2 logarithm of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::log2`](../../std/primitive.f64.html#method.log2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log2f64(x: f64) -> f64;
+pub fn log2f64(x: f64) -> f64;
 /// Returns the base 2 logarithm of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::log2`](../../std/primitive.f128.html#method.log2)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn log2f128(x: f128) -> f128;
+pub fn log2f128(x: f128) -> f128;
 
 /// Returns `a * b + c` for `f16` values.
 ///
@@ -1312,28 +1312,28 @@ pub unsafe fn log2f128(x: f128) -> f128;
 /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmaf16(a: f16, b: f16, c: f16) -> f16;
+pub const fn fmaf16(a: f16, b: f16, c: f16) -> f16;
 /// Returns `a * b + c` for `f32` values.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmaf32(a: f32, b: f32, c: f32) -> f32;
+pub const fn fmaf32(a: f32, b: f32, c: f32) -> f32;
 /// Returns `a * b + c` for `f64` values.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmaf64(a: f64, b: f64, c: f64) -> f64;
+pub const fn fmaf64(a: f64, b: f64, c: f64) -> f64;
 /// Returns `a * b + c` for `f128` values.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add)
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmaf128(a: f128, b: f128, c: f128) -> f128;
+pub const fn fmaf128(a: f128, b: f128, c: f128) -> f128;
 
 /// Returns `a * b + c` for `f16` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
@@ -1347,7 +1347,7 @@ pub unsafe fn fmaf128(a: f128, b: f128, c: f128) -> f128;
 /// example.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf16(a: f16, b: f16, c: f16) -> f16;
+pub const fn fmuladdf16(a: f16, b: f16, c: f16) -> f16;
 /// Returns `a * b + c` for `f32` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
 /// intermediate result.
@@ -1360,7 +1360,7 @@ pub unsafe fn fmuladdf16(a: f16, b: f16, c: f16) -> f16;
 /// example.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf32(a: f32, b: f32, c: f32) -> f32;
+pub const fn fmuladdf32(a: f32, b: f32, c: f32) -> f32;
 /// Returns `a * b + c` for `f64` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
 /// intermediate result.
@@ -1373,7 +1373,7 @@ pub unsafe fn fmuladdf32(a: f32, b: f32, c: f32) -> f32;
 /// example.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf64(a: f64, b: f64, c: f64) -> f64;
+pub const fn fmuladdf64(a: f64, b: f64, c: f64) -> f64;
 /// Returns `a * b + c` for `f128` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
 /// intermediate result.
@@ -1386,7 +1386,7 @@ pub unsafe fn fmuladdf64(a: f64, b: f64, c: f64) -> f64;
 /// example.
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128;
+pub const fn fmuladdf128(a: f128, b: f128, c: f128) -> f128;
 
 /// Returns the largest integer less than or equal to an `f16`.
 ///
@@ -1395,7 +1395,7 @@ pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn floorf16(x: f16) -> f16;
+pub const fn floorf16(x: f16) -> f16;
 /// Returns the largest integer less than or equal to an `f32`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1403,7 +1403,7 @@ pub const unsafe fn floorf16(x: f16) -> f16;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn floorf32(x: f32) -> f32;
+pub const fn floorf32(x: f32) -> f32;
 /// Returns the largest integer less than or equal to an `f64`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1411,7 +1411,7 @@ pub const unsafe fn floorf32(x: f32) -> f32;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn floorf64(x: f64) -> f64;
+pub const fn floorf64(x: f64) -> f64;
 /// Returns the largest integer less than or equal to an `f128`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1419,7 +1419,7 @@ pub const unsafe fn floorf64(x: f64) -> f64;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn floorf128(x: f128) -> f128;
+pub const fn floorf128(x: f128) -> f128;
 
 /// Returns the smallest integer greater than or equal to an `f16`.
 ///
@@ -1428,7 +1428,7 @@ pub const unsafe fn floorf128(x: f128) -> f128;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn ceilf16(x: f16) -> f16;
+pub const fn ceilf16(x: f16) -> f16;
 /// Returns the smallest integer greater than or equal to an `f32`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1436,7 +1436,7 @@ pub const unsafe fn ceilf16(x: f16) -> f16;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn ceilf32(x: f32) -> f32;
+pub const fn ceilf32(x: f32) -> f32;
 /// Returns the smallest integer greater than or equal to an `f64`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1444,7 +1444,7 @@ pub const unsafe fn ceilf32(x: f32) -> f32;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn ceilf64(x: f64) -> f64;
+pub const fn ceilf64(x: f64) -> f64;
 /// Returns the smallest integer greater than or equal to an `f128`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1452,7 +1452,7 @@ pub const unsafe fn ceilf64(x: f64) -> f64;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn ceilf128(x: f128) -> f128;
+pub const fn ceilf128(x: f128) -> f128;
 
 /// Returns the integer part of an `f16`.
 ///
@@ -1461,7 +1461,7 @@ pub const unsafe fn ceilf128(x: f128) -> f128;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn truncf16(x: f16) -> f16;
+pub const fn truncf16(x: f16) -> f16;
 /// Returns the integer part of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1469,7 +1469,7 @@ pub const unsafe fn truncf16(x: f16) -> f16;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn truncf32(x: f32) -> f32;
+pub const fn truncf32(x: f32) -> f32;
 /// Returns the integer part of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1477,7 +1477,7 @@ pub const unsafe fn truncf32(x: f32) -> f32;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn truncf64(x: f64) -> f64;
+pub const fn truncf64(x: f64) -> f64;
 /// Returns the integer part of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
@@ -1485,7 +1485,7 @@ pub const unsafe fn truncf64(x: f64) -> f64;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn truncf128(x: f128) -> f128;
+pub const fn truncf128(x: f128) -> f128;
 
 /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number with an even
 /// least significant digit.
@@ -1534,7 +1534,7 @@ pub const fn round_ties_even_f128(x: f128) -> f128;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn roundf16(x: f16) -> f16;
+pub const fn roundf16(x: f16) -> f16;
 /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero.
 ///
 /// The stabilized version of this intrinsic is
@@ -1542,7 +1542,7 @@ pub const unsafe fn roundf16(x: f16) -> f16;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn roundf32(x: f32) -> f32;
+pub const fn roundf32(x: f32) -> f32;
 /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero.
 ///
 /// The stabilized version of this intrinsic is
@@ -1550,7 +1550,7 @@ pub const unsafe fn roundf32(x: f32) -> f32;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn roundf64(x: f64) -> f64;
+pub const fn roundf64(x: f64) -> f64;
 /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero.
 ///
 /// The stabilized version of this intrinsic is
@@ -1558,10 +1558,10 @@ pub const unsafe fn roundf64(x: f64) -> f64;
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub const unsafe fn roundf128(x: f128) -> f128;
+pub const fn roundf128(x: f128) -> f128;
 
 /// Float addition that allows optimizations based on algebraic rules.
-/// May assume inputs are finite.
+/// Requires that inputs and output of the operation are finite, causing UB otherwise.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
@@ -1569,7 +1569,7 @@ pub const unsafe fn roundf128(x: f128) -> f128;
 pub unsafe fn fadd_fast<T: Copy>(a: T, b: T) -> T;
 
 /// Float subtraction that allows optimizations based on algebraic rules.
-/// May assume inputs are finite.
+/// Requires that inputs and output of the operation are finite, causing UB otherwise.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
@@ -1577,7 +1577,7 @@ pub unsafe fn fadd_fast<T: Copy>(a: T, b: T) -> T;
 pub unsafe fn fsub_fast<T: Copy>(a: T, b: T) -> T;
 
 /// Float multiplication that allows optimizations based on algebraic rules.
-/// May assume inputs are finite.
+/// Requires that inputs and output of the operation are finite, causing UB otherwise.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
@@ -1585,7 +1585,7 @@ pub unsafe fn fsub_fast<T: Copy>(a: T, b: T) -> T;
 pub unsafe fn fmul_fast<T: Copy>(a: T, b: T) -> T;
 
 /// Float division that allows optimizations based on algebraic rules.
-/// May assume inputs are finite.
+/// Requires that inputs and output of the operation are finite, causing UB otherwise.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
@@ -1593,7 +1593,7 @@ pub unsafe fn fmul_fast<T: Copy>(a: T, b: T) -> T;
 pub unsafe fn fdiv_fast<T: Copy>(a: T, b: T) -> T;
 
 /// Float remainder that allows optimizations based on algebraic rules.
-/// May assume inputs are finite.
+/// Requires that inputs and output of the operation are finite, causing UB otherwise.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
@@ -3170,7 +3170,7 @@ pub const fn maximumf128(x: f128, y: f128) -> f128 {
 /// [`f16::abs`](../../std/primitive.f16.html#method.abs)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-pub const unsafe fn fabsf16(x: f16) -> f16;
+pub const fn fabsf16(x: f16) -> f16;
 
 /// Returns the absolute value of an `f32`.
 ///
@@ -3179,7 +3179,7 @@ pub const unsafe fn fabsf16(x: f16) -> f16;
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-pub const unsafe fn fabsf32(x: f32) -> f32;
+pub const fn fabsf32(x: f32) -> f32;
 
 /// Returns the absolute value of an `f64`.
 ///
@@ -3188,7 +3188,7 @@ pub const unsafe fn fabsf32(x: f32) -> f32;
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-pub const unsafe fn fabsf64(x: f64) -> f64;
+pub const fn fabsf64(x: f64) -> f64;
 
 /// Returns the absolute value of an `f128`.
 ///
@@ -3196,7 +3196,7 @@ pub const unsafe fn fabsf64(x: f64) -> f64;
 /// [`f128::abs`](../../std/primitive.f128.html#method.abs)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-pub const unsafe fn fabsf128(x: f128) -> f128;
+pub const fn fabsf128(x: f128) -> f128;
 
 /// Copies the sign from `y` to `x` for `f16` values.
 ///
@@ -3204,7 +3204,7 @@ pub const unsafe fn fabsf128(x: f128) -> f128;
 /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-pub const unsafe fn copysignf16(x: f16, y: f16) -> f16;
+pub const fn copysignf16(x: f16, y: f16) -> f16;
 
 /// Copies the sign from `y` to `x` for `f32` values.
 ///
@@ -3213,7 +3213,7 @@ pub const unsafe fn copysignf16(x: f16, y: f16) -> f16;
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-pub const unsafe fn copysignf32(x: f32, y: f32) -> f32;
+pub const fn copysignf32(x: f32, y: f32) -> f32;
 /// Copies the sign from `y` to `x` for `f64` values.
 ///
 /// The stabilized version of this intrinsic is
@@ -3221,7 +3221,7 @@ pub const unsafe fn copysignf32(x: f32, y: f32) -> f32;
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-pub const unsafe fn copysignf64(x: f64, y: f64) -> f64;
+pub const fn copysignf64(x: f64, y: f64) -> f64;
 
 /// Copies the sign from `y` to `x` for `f128` values.
 ///
@@ -3229,7 +3229,7 @@ pub const unsafe fn copysignf64(x: f64, y: f64) -> f64;
 /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-pub const unsafe fn copysignf128(x: f128, y: f128) -> f128;
+pub const fn copysignf128(x: f128, y: f128) -> f128;
 
 /// Generates the LLVM body for the automatic differentiation of `f` using Enzyme,
 /// with `df` as the derivative function and `args` as its arguments.
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index a820045521b..c50f07ff6bb 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -779,7 +779,7 @@ impl<T> OneShot for result::IterMut<'_, T> {}
 impl<T> OneShot for Empty<T> {}
 impl<T> OneShot for array::IntoIter<T, 0> {}
 
-// These adaptors never increase the number of items.
+// These adapters never increase the number of items.
 // (There are more possible, but for now this matches BoundedSize above.)
 impl<I: OneShot> OneShot for Cloned<I> {}
 impl<I: OneShot> OneShot for Copied<I> {}
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 66c892aadd0..73ca3fbb142 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -1196,7 +1196,8 @@ impl f128 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
-    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
         let mut left = self.to_bits() as i128;
         let mut right = other.to_bits() as i128;
 
@@ -1366,8 +1367,7 @@ impl f128 {
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn copysign(self, sign: f128) -> f128 {
-        // SAFETY: this is actually a safe intrinsic
-        unsafe { intrinsics::copysignf128(self, sign) }
+        intrinsics::copysignf128(self, sign)
     }
 
     /// Float addition that allows optimizations based on algebraic rules.
@@ -1459,8 +1459,7 @@ impl f128 {
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(self) -> f128 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::floorf128(self) }
+        intrinsics::floorf128(self)
     }
 
     /// Returns the smallest integer greater than or equal to `self`.
@@ -1488,8 +1487,7 @@ impl f128 {
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn ceil(self) -> f128 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::ceilf128(self) }
+        intrinsics::ceilf128(self)
     }
 
     /// Returns the nearest integer to `self`. If a value is half-way between two
@@ -1523,8 +1521,7 @@ impl f128 {
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round(self) -> f128 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::roundf128(self) }
+        intrinsics::roundf128(self)
     }
 
     /// Returns the nearest integer to a number. Rounds half-way cases to the number
@@ -1587,8 +1584,7 @@ impl f128 {
     #[rustc_const_unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn trunc(self) -> f128 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::truncf128(self) }
+        intrinsics::truncf128(self)
     }
 
     /// Returns the fractional part of `self`.
@@ -1663,9 +1659,9 @@ impl f128 {
     #[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")]
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    pub fn mul_add(self, a: f128, b: f128) -> f128 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::fmaf128(self, a, b) }
+    #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")]
+    pub const fn mul_add(self, a: f128, b: f128) -> f128 {
+        intrinsics::fmaf128(self, a, b)
     }
 
     /// Calculates Euclidean division, the matching method for `rem_euclid`.
@@ -1780,8 +1776,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn powi(self, n: i32) -> f128 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::powif128(self, n) }
+        intrinsics::powif128(self, n)
     }
 
     /// Returns the square root of a number.
@@ -1816,7 +1811,6 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sqrt(self) -> f128 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::sqrtf128(self) }
+        intrinsics::sqrtf128(self)
     }
 }
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 81220065e72..a9dbade0e65 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -1175,7 +1175,8 @@ impl f16 {
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
-    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
         let mut left = self.to_bits() as i16;
         let mut right = other.to_bits() as i16;
 
@@ -1343,8 +1344,7 @@ impl f16 {
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn copysign(self, sign: f16) -> f16 {
-        // SAFETY: this is actually a safe intrinsic
-        unsafe { intrinsics::copysignf16(self, sign) }
+        intrinsics::copysignf16(self, sign)
     }
 
     /// Float addition that allows optimizations based on algebraic rules.
@@ -1434,8 +1434,7 @@ impl f16 {
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(self) -> f16 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::floorf16(self) }
+        intrinsics::floorf16(self)
     }
 
     /// Returns the smallest integer greater than or equal to `self`.
@@ -1463,8 +1462,7 @@ impl f16 {
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn ceil(self) -> f16 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::ceilf16(self) }
+        intrinsics::ceilf16(self)
     }
 
     /// Returns the nearest integer to `self`. If a value is half-way between two
@@ -1498,8 +1496,7 @@ impl f16 {
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round(self) -> f16 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::roundf16(self) }
+        intrinsics::roundf16(self)
     }
 
     /// Returns the nearest integer to a number. Rounds half-way cases to the number
@@ -1562,8 +1559,7 @@ impl f16 {
     #[rustc_const_unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn trunc(self) -> f16 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::truncf16(self) }
+        intrinsics::truncf16(self)
     }
 
     /// Returns the fractional part of `self`.
@@ -1638,9 +1634,9 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[doc(alias = "fmaf16", alias = "fusedMultiplyAdd")]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    pub fn mul_add(self, a: f16, b: f16) -> f16 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::fmaf16(self, a, b) }
+    #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")]
+    pub const fn mul_add(self, a: f16, b: f16) -> f16 {
+        intrinsics::fmaf16(self, a, b)
     }
 
     /// Calculates Euclidean division, the matching method for `rem_euclid`.
@@ -1755,8 +1751,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn powi(self, n: i32) -> f16 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::powif16(self, n) }
+        intrinsics::powif16(self, n)
     }
 
     /// Returns the square root of a number.
@@ -1791,8 +1786,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sqrt(self) -> f16 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::sqrtf16(self) }
+        intrinsics::sqrtf16(self)
     }
 
     /// Returns the cube root of a number.
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index cefcf1d1fe2..53474cd3e90 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1353,9 +1353,10 @@ impl f32 {
     /// }
     /// ```
     #[stable(feature = "total_cmp", since = "1.62.0")]
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
     #[must_use]
     #[inline]
-    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
+    pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
         let mut left = self.to_bits() as i32;
         let mut right = other.to_bits() as i32;
 
@@ -1449,8 +1450,7 @@ impl f32 {
     #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")]
     #[inline]
     pub const fn abs(self) -> f32 {
-        // SAFETY: this is actually a safe intrinsic
-        unsafe { intrinsics::fabsf32(self) }
+        intrinsics::fabsf32(self)
     }
 
     /// Returns a number that represents the sign of `self`.
@@ -1508,8 +1508,7 @@ impl f32 {
     #[stable(feature = "copysign", since = "1.35.0")]
     #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")]
     pub const fn copysign(self, sign: f32) -> f32 {
-        // SAFETY: this is actually a safe intrinsic
-        unsafe { intrinsics::copysignf32(self, sign) }
+        intrinsics::copysignf32(self, sign)
     }
 
     /// Float addition that allows optimizations based on algebraic rules.
@@ -1603,8 +1602,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(x: f32) -> f32 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::floorf32(x) }
+        intrinsics::floorf32(x)
     }
 
     /// Experimental version of `ceil` in `core`. See [`f32::ceil`] for details.
@@ -1632,8 +1630,7 @@ pub mod math {
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "core_float_math", issue = "137578")]
     pub const fn ceil(x: f32) -> f32 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::ceilf32(x) }
+        intrinsics::ceilf32(x)
     }
 
     /// Experimental version of `round` in `core`. See [`f32::round`] for details.
@@ -1666,8 +1663,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round(x: f32) -> f32 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::roundf32(x) }
+        intrinsics::roundf32(x)
     }
 
     /// Experimental version of `round_ties_even` in `core`. See [`f32::round_ties_even`] for
@@ -1729,8 +1725,7 @@ pub mod math {
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "core_float_math", issue = "137578")]
     pub const fn trunc(x: f32) -> f32 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::truncf32(x) }
+        intrinsics::truncf32(x)
     }
 
     /// Experimental version of `fract` in `core`. See [`f32::fract`] for details.
@@ -1803,9 +1798,9 @@ pub mod math {
     #[doc(alias = "fmaf", alias = "fusedMultiplyAdd")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "core_float_math", issue = "137578")]
-    pub fn mul_add(x: f32, y: f32, z: f32) -> f32 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::fmaf32(x, y, z) }
+    #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")]
+    pub const fn mul_add(x: f32, y: f32, z: f32) -> f32 {
+        intrinsics::fmaf32(x, y, z)
     }
 
     /// Experimental version of `div_euclid` in `core`. See [`f32::div_euclid`] for details.
@@ -1896,8 +1891,7 @@ pub mod math {
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[unstable(feature = "core_float_math", issue = "137578")]
     pub fn powi(x: f32, n: i32) -> f32 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::powif32(x, n) }
+        intrinsics::powif32(x, n)
     }
 
     /// Experimental version of `sqrt` in `core`. See [`f32::sqrt`] for details.
@@ -1927,8 +1921,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sqrt(x: f32) -> f32 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::sqrtf32(x) }
+        intrinsics::sqrtf32(x)
     }
 
     /// Experimental version of `abs_sub` in `core`. See [`f32::abs_sub`] for details.
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 9dd1141e703..78113a60bbc 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1351,9 +1351,10 @@ impl f64 {
     /// }
     /// ```
     #[stable(feature = "total_cmp", since = "1.62.0")]
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
     #[must_use]
     #[inline]
-    pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
+    pub const fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
         let mut left = self.to_bits() as i64;
         let mut right = other.to_bits() as i64;
 
@@ -1447,8 +1448,7 @@ impl f64 {
     #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")]
     #[inline]
     pub const fn abs(self) -> f64 {
-        // SAFETY: this is actually a safe intrinsic
-        unsafe { intrinsics::fabsf64(self) }
+        intrinsics::fabsf64(self)
     }
 
     /// Returns a number that represents the sign of `self`.
@@ -1506,8 +1506,7 @@ impl f64 {
     #[rustc_const_stable(feature = "const_float_methods", since = "1.85.0")]
     #[inline]
     pub const fn copysign(self, sign: f64) -> f64 {
-        // SAFETY: this is actually a safe intrinsic
-        unsafe { intrinsics::copysignf64(self, sign) }
+        intrinsics::copysignf64(self, sign)
     }
 
     /// Float addition that allows optimizations based on algebraic rules.
@@ -1601,8 +1600,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn floor(x: f64) -> f64 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::floorf64(x) }
+        intrinsics::floorf64(x)
     }
 
     /// Experimental version of `ceil` in `core`. See [`f64::ceil`] for details.
@@ -1630,8 +1628,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn ceil(x: f64) -> f64 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::ceilf64(x) }
+        intrinsics::ceilf64(x)
     }
 
     /// Experimental version of `round` in `core`. See [`f64::round`] for details.
@@ -1664,8 +1661,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn round(x: f64) -> f64 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::roundf64(x) }
+        intrinsics::roundf64(x)
     }
 
     /// Experimental version of `round_ties_even` in `core`. See [`f64::round_ties_even`] for
@@ -1727,8 +1723,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub const fn trunc(x: f64) -> f64 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::truncf64(x) }
+        intrinsics::truncf64(x)
     }
 
     /// Experimental version of `fract` in `core`. See [`f64::fract`] for details.
@@ -1801,9 +1796,9 @@ pub mod math {
     #[doc(alias = "fma", alias = "fusedMultiplyAdd")]
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
-    pub fn mul_add(x: f64, a: f64, b: f64) -> f64 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::fmaf64(x, a, b) }
+    #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")]
+    pub const fn mul_add(x: f64, a: f64, b: f64) -> f64 {
+        intrinsics::fmaf64(x, a, b)
     }
 
     /// Experimental version of `div_euclid` in `core`. See [`f64::div_euclid`] for details.
@@ -1894,8 +1889,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn powi(x: f64, n: i32) -> f64 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::powif64(x, n) }
+        intrinsics::powif64(x, n)
     }
 
     /// Experimental version of `sqrt` in `core`. See [`f64::sqrt`] for details.
@@ -1925,8 +1919,7 @@ pub mod math {
     #[unstable(feature = "core_float_math", issue = "137578")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sqrt(x: f64) -> f64 {
-        // SAFETY: intrinsic with no preconditions
-        unsafe { intrinsics::sqrtf64(x) }
+        intrinsics::sqrtf64(x)
     }
 
     /// Experimental version of `abs_sub` in `core`. See [`f64::abs_sub`] for details.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 64a3dd3e8bc..0d80c40fb23 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1460,8 +1460,8 @@ macro_rules! int_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
-                concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out non-zero bits"),
+                check_library_ub,
+                concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out bits that would change the value of the first bit"),
                 (
                     zeros: u32 = self.leading_zeros(),
                     ones: u32 = self.leading_ones(),
@@ -1638,7 +1638,7 @@ macro_rules! int_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
+                check_library_ub,
                 concat!(stringify!($SelfT), "::unchecked_exact_shr cannot shift out non-zero bits"),
                 (
                     zeros: u32 = self.trailing_zeros(),
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 54d5a63633c..c75ee11d15e 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -1387,8 +1387,8 @@ pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8])
     radix <= 16 && digits.len() <= size_of::<T>() * 2 - is_signed_ty as usize
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[cold]
 #[track_caller]
 const fn from_ascii_radix_panic(radix: u32) -> ! {
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 1b7c28bb95a..d9184e3c9c2 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -548,6 +548,18 @@ macro_rules! nonzero_integer {
         #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")]
         /// ```
         ///
+        /// # Compile-time creation
+        ///
+        /// Since both [`Option::unwrap()`] and [`Option::expect()`] are `const`, it is possible to
+        /// define a new
+        #[doc = concat!("`", stringify!($Ty), "`")]
+        /// at compile time via:
+        /// ```
+        #[doc = concat!("use std::num::", stringify!($Ty), ";")]
+        ///
+        #[doc = concat!("const TEN: ", stringify!($Ty), " = ", stringify!($Ty) , r#"::new(10).expect("ten is non-zero");"#)]
+        /// ```
+        ///
         /// [null pointer optimization]: crate::option#representation
         #[$stability]
         pub type $Ty = NonZero<$Int>;
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index bf72ec83197..d68c7be9865 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1865,7 +1865,7 @@ macro_rules! uint_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
+                check_library_ub,
                 concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
                 (
                     zeros: u32 = self.leading_zeros(),
@@ -2037,7 +2037,7 @@ macro_rules! uint_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
+                check_library_ub,
                 concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
                 (
                     zeros: u32 = self.trailing_zeros(),
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 886d581b0a6..430ee3470ac 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2161,8 +2161,8 @@ impl<T, E> Option<Result<T, E>> {
     }
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[cold]
 #[track_caller]
 const fn unwrap_failed() -> ! {
@@ -2170,8 +2170,8 @@ const fn unwrap_failed() -> ! {
 }
 
 // This is a separate function to reduce the code size of .expect() itself.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[cold]
 #[track_caller]
 const fn expect_failed(msg: &str) -> ! {
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 804a12ee477..3f30038dbc0 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -33,7 +33,10 @@ use crate::intrinsics::const_eval_select;
 use crate::panic::{Location, PanicInfo};
 
 #[cfg(feature = "panic_immediate_abort")]
-const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort");
+compile_error!(
+    "panic_immediate_abort is now a real panic strategy! \
+    Enable it with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`"
+);
 
 // First we define the two main entry points that all panics go through.
 // In the end both are just convenience wrappers around `panic_impl`.
@@ -44,16 +47,16 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C
 /// site as much as possible (so that `panic!()` has as low an impact
 /// on (e.g.) the inlining of other functions as possible), by moving
 /// the actual formatting into this shared place.
-// If panic_immediate_abort, inline the abort call,
+// If panic=immediate-abort, inline the abort call,
 // otherwise avoid inlining because of it is cold path.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[lang = "panic_fmt"] // needed for const-evaluated panics
 #[rustc_do_not_const_check] // hooked by const-eval
 #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable
 pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
+    if cfg!(panic = "immediate-abort") {
         super::intrinsics::abort()
     }
 
@@ -78,8 +81,8 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
 /// Like `panic_fmt`, but for non-unwinding panics.
 ///
 /// Has to be a separate function so that it can carry the `rustc_nounwind` attribute.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 // This attribute has the key side-effect that if the panic handler ignores `can_unwind`
 // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
@@ -94,7 +97,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
             // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`.
             panic_fmt(fmt)
         } else #[track_caller] {
-            if cfg!(feature = "panic_immediate_abort") {
+            if cfg!(panic = "immediate-abort") {
                 super::intrinsics::abort()
             }
 
@@ -123,10 +126,10 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
 // above.
 
 /// The underlying implementation of core's `panic!` macro when no formatting is used.
-// Never inline unless panic_immediate_abort to avoid code
+// Never inline unless panic=immediate-abort to avoid code
 // bloat at the call sites as much as possible.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable
 #[lang = "panic"] // used by lints and miri for panics
@@ -158,10 +161,10 @@ macro_rules! panic_const {
         $(
             /// This is a panic called with a message that's a result of a MIR-produced Assert.
             //
-            // never inline unless panic_immediate_abort to avoid code
+            // never inline unless panic=immediate-abort to avoid code
             // bloat at the call sites as much as possible
-            #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-            #[cfg_attr(feature = "panic_immediate_abort", inline)]
+            #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+            #[cfg_attr(panic = "immediate-abort", inline)]
             #[track_caller]
             #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable
             #[lang = stringify!($lang)]
@@ -216,8 +219,8 @@ pub mod panic_const {
 
 /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
 /// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
 #[rustc_nounwind]
 #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable
@@ -226,8 +229,8 @@ pub const fn panic_nounwind(expr: &'static str) -> ! {
 }
 
 /// Like `panic_nounwind`, but also inhibits showing a backtrace.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[rustc_nounwind]
 pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
     panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true);
@@ -259,25 +262,25 @@ pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
     panic_fmt(format_args!("{}", *x));
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
 fn panic_bounds_check(index: usize, len: usize) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
+    if cfg!(panic = "immediate-abort") {
         super::intrinsics::abort()
     }
 
     panic!("index out of bounds: the len is {len} but the index is {index}")
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref
 #[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind
 fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
+    if cfg!(panic = "immediate-abort") {
         super::intrinsics::abort()
     }
 
@@ -289,13 +292,13 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
     )
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[lang = "panic_null_pointer_dereference"] // needed by codegen for panic on null pointer deref
 #[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind
 fn panic_null_pointer_dereference() -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
+    if cfg!(panic = "immediate-abort") {
         super::intrinsics::abort()
     }
 
@@ -305,13 +308,13 @@ fn panic_null_pointer_dereference() -> ! {
     )
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[lang = "panic_invalid_enum_construction"] // needed by codegen for panic on invalid enum construction.
 #[rustc_nounwind] // `CheckEnums` MIR pass requires this function to never unwind
 fn panic_invalid_enum_construction(source: u128) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
+    if cfg!(panic = "immediate-abort") {
         super::intrinsics::abort()
     }
 
@@ -328,8 +331,8 @@ fn panic_invalid_enum_construction(source: u128) -> ! {
 ///
 /// This function is called directly by the codegen backend, and must not have
 /// any extra arguments (including those synthesized by track_caller).
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[lang = "panic_cannot_unwind"] // needed by codegen for panic in nounwind function
 #[rustc_nounwind]
 fn panic_cannot_unwind() -> ! {
@@ -344,8 +347,8 @@ fn panic_cannot_unwind() -> ! {
 ///
 /// This function is called directly by the codegen backend, and must not have
 /// any extra arguments (including those synthesized by track_caller).
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function
 #[rustc_nounwind]
 fn panic_in_cleanup() -> ! {
@@ -377,8 +380,8 @@ pub enum AssertKind {
 }
 
 /// Internal function for `assert_eq!` and `assert_ne!` macros
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[doc(hidden)]
 pub fn assert_failed<T, U>(
@@ -395,8 +398,8 @@ where
 }
 
 /// Internal function for `assert_match!`
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[doc(hidden)]
 pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
@@ -415,8 +418,8 @@ pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
 }
 
 /// Non-generic version of the above functions, to avoid code bloat.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 fn assert_failed_inner(
     kind: AssertKind,
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 5c1f64bfe14..c69762a7285 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1847,7 +1847,7 @@ impl<T, E> Result<Result<T, E>, E> {
 }
 
 // This is a separate function to reduce the code size of the methods
-#[cfg(not(feature = "panic_immediate_abort"))]
+#[cfg(not(panic = "immediate-abort"))]
 #[inline(never)]
 #[cold]
 #[track_caller]
@@ -1859,7 +1859,7 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
 // that gets immediately thrown away, since vtables don't get cleaned up
 // by dead code elimination if a trait object is constructed even if it goes
 // unused
-#[cfg(feature = "panic_immediate_abort")]
+#[cfg(panic = "immediate-abort")]
 #[inline]
 #[cold]
 #[track_caller]
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index a8147d745f3..de220e7e38a 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -31,8 +31,8 @@ where
     }
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 const fn slice_index_fail(start: usize, end: usize, len: usize) -> ! {
     if start > len {
@@ -233,7 +233,7 @@ unsafe impl<T> const SliceIndex<[T]> for usize {
     #[track_caller]
     unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
         assert_unsafe_precondition!(
-            check_language_ub,
+            check_language_ub, // okay because of the `assume` below
             "slice::get_unchecked requires that the index is within the slice",
             (this: usize = self, len: usize = slice.len()) => this < len
         );
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index dfbb3628350..f7f5ee819b2 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3858,8 +3858,8 @@ impl<T> [T] {
     {
         // The panic code path was put into a cold function to not bloat the
         // call site.
-        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-        #[cfg_attr(feature = "panic_immediate_abort", inline)]
+        #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+        #[cfg_attr(panic = "immediate-abort", inline)]
         #[track_caller]
         const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! {
             const_panic!(
diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs
index 400daba16c1..e555fce4408 100644
--- a/library/core/src/slice/sort/shared/smallsort.rs
+++ b/library/core/src/slice/sort/shared/smallsort.rs
@@ -840,8 +840,8 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>(
     }
 }
 
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 fn panic_on_ord_violation() -> ! {
     // This is indicative of a logic bug in the user-provided comparison function or Ord
     // implementation. They are expected to implement a total order as explained in the Ord
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 04fdaa8143e..2e473d348b0 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -64,12 +64,12 @@ pub use validations::{next_code_point, utf8_char_width};
 #[cold]
 #[track_caller]
 #[rustc_allow_const_fn_unstable(const_eval_select)]
-#[cfg(not(feature = "panic_immediate_abort"))]
+#[cfg(not(panic = "immediate-abort"))]
 const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     crate::intrinsics::const_eval_select((s, begin, end), slice_error_fail_ct, slice_error_fail_rt)
 }
 
-#[cfg(feature = "panic_immediate_abort")]
+#[cfg(panic = "immediate-abort")]
 const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     slice_error_fail_ct(s, begin, end)
 }
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index b809294cfce..514ff93c982 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -21,8 +21,9 @@ use crate::intrinsics::{self, const_eval_select};
 /// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice
 /// diagnostic, but our ability to detect UB is unchanged.
 /// But if `check_language_ub` is used when the check is actually for library UB, the check is
-/// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the
-/// library UB, the backtrace Miri reports may be far removed from original cause.
+/// omitted in const-eval/Miri and thus UB might occur undetected. Even if we eventually execute
+/// language UB which relies on the library UB, the backtrace Miri reports may be far removed from
+/// original cause.
 ///
 /// These checks are behind a condition which is evaluated at codegen time, not expansion time like
 /// [`debug_assert`]. This means that a standard library built with optimizations and debug
diff --git a/library/coretests/tests/atomic.rs b/library/coretests/tests/atomic.rs
index b1ab443aa6e..d888bd0f55a 100644
--- a/library/coretests/tests/atomic.rs
+++ b/library/coretests/tests/atomic.rs
@@ -12,6 +12,38 @@ fn bool_() {
 }
 
 #[test]
+#[should_panic = "there is no such thing as an acquire store"]
+fn store_illegal_rt_store_acquire_ordering() {
+    let a = AtomicBool::new(false);
+    let ord = Ordering::Acquire;
+    a.store(true, ord);
+}
+
+#[test]
+#[should_panic = "there is no such thing as an acquire-release store"]
+fn store_illegal_rt_store_acq_rel_ordering() {
+    let a = AtomicBool::new(false);
+    let ord = Ordering::AcqRel;
+    a.store(true, ord);
+}
+
+#[test]
+#[should_panic = "there is no such thing as a release load"]
+fn store_illegal_rt_load_release_ordering() {
+    let a = AtomicBool::new(false);
+    let ord = Ordering::Release;
+    a.load(ord);
+}
+
+#[test]
+#[should_panic = "there is no such thing as an acquire-release load"]
+fn store_illegal_rt_load_acq_rel_ordering() {
+    let a = AtomicBool::new(false);
+    let ord = Ordering::AcqRel;
+    a.load(ord);
+}
+
+#[test]
 fn bool_and() {
     let a = AtomicBool::new(true);
     assert_eq!(a.fetch_and(false, SeqCst), true);
@@ -283,25 +315,229 @@ fn atomic_compare_exchange() {
     static ATOMIC: AtomicIsize = AtomicIsize::new(0);
 
     ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, Relaxed, Acquire).ok();
+    ATOMIC.compare_exchange(0, 1, Relaxed, SeqCst).ok();
     ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
+    ATOMIC.compare_exchange(0, 1, Acquire, SeqCst).ok();
     ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, Release, Acquire).ok();
+    ATOMIC.compare_exchange(0, 1, Release, SeqCst).ok();
     ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok();
-    ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
-    ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
     ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok();
+    ATOMIC.compare_exchange(0, 1, AcqRel, SeqCst).ok();
+    ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
     ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok();
     ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok();
     ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Relaxed, Acquire).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Relaxed, SeqCst).ok();
     ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Acquire, SeqCst).ok();
     ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Release, Acquire).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Release, SeqCst).ok();
     ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok();
-    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
-    ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
     ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok();
+    ATOMIC.compare_exchange_weak(0, 1, AcqRel, SeqCst).ok();
+    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
     ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
     ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
 }
 
+#[test]
+#[should_panic = "there is no such thing as an acquire-release failure ordering"]
+fn atomic_compare_exchange_illegal_acq_rel() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicIsize = AtomicIsize::new(0);
+
+    let failure = AcqRel;
+
+    ATOMIC.compare_exchange(0, 1, Relaxed, failure).ok();
+}
+
+#[test]
+#[should_panic = "there is no such thing as a release failure ordering"]
+fn atomic_compare_exchange_illegal_release() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicIsize = AtomicIsize::new(0);
+
+    let failure = Release;
+
+    ATOMIC.compare_exchange(0, 1, Relaxed, failure).ok();
+}
+
+#[test]
+#[should_panic = "there is no such thing as an acquire-release failure ordering"]
+fn atomic_compare_exchange_weak_illegal_acq_rel() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicIsize = AtomicIsize::new(0);
+
+    let failure = AcqRel;
+
+    ATOMIC.compare_exchange_weak(0, 1, Relaxed, failure).ok();
+}
+
+#[test]
+#[should_panic = "there is no such thing as a release failure ordering"]
+fn atomic_compare_exchange_weak_illegal_release() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicIsize = AtomicIsize::new(0);
+
+    let failure = Release;
+
+    ATOMIC.compare_exchange_weak(0, 1, Relaxed, failure).ok();
+}
+
+#[test]
+fn atomic_swap() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicBool = AtomicBool::new(false);
+
+    assert_eq!(ATOMIC.swap(true, Relaxed), false);
+    assert_eq!(ATOMIC.swap(false, Acquire), true);
+    assert_eq!(ATOMIC.swap(true, Release), false);
+    assert_eq!(ATOMIC.swap(false, AcqRel), true);
+    assert_eq!(ATOMIC.swap(true, SeqCst), false);
+}
+
+#[test]
+fn atomic_add() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicU8 = AtomicU8::new(0);
+
+    assert_eq!(ATOMIC.fetch_add(1, Relaxed), 0);
+    assert_eq!(ATOMIC.fetch_add(1, Acquire), 1);
+    assert_eq!(ATOMIC.fetch_add(1, Release), 2);
+    assert_eq!(ATOMIC.fetch_add(1, AcqRel), 3);
+    assert_eq!(ATOMIC.fetch_add(1, SeqCst), 4);
+    assert_eq!(ATOMIC.load(Relaxed), 5);
+}
+
+#[test]
+fn atomic_sub() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicU8 = AtomicU8::new(5);
+
+    assert_eq!(ATOMIC.fetch_sub(1, Relaxed), 5);
+    assert_eq!(ATOMIC.fetch_sub(1, Acquire), 4);
+    assert_eq!(ATOMIC.fetch_sub(1, Release), 3);
+    assert_eq!(ATOMIC.fetch_sub(1, AcqRel), 2);
+    assert_eq!(ATOMIC.fetch_sub(1, SeqCst), 1);
+    assert_eq!(ATOMIC.load(Relaxed), 0);
+}
+
+#[test]
+fn atomic_and_or() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicBool = AtomicBool::new(false);
+
+    assert_eq!(ATOMIC.fetch_or(true, Relaxed), false);
+    assert_eq!(ATOMIC.fetch_and(false, Relaxed), true);
+    assert_eq!(ATOMIC.fetch_or(true, Acquire), false);
+    assert_eq!(ATOMIC.fetch_and(false, Acquire), true);
+    assert_eq!(ATOMIC.fetch_or(true, Release), false);
+    assert_eq!(ATOMIC.fetch_and(false, Release), true);
+    assert_eq!(ATOMIC.fetch_or(true, AcqRel), false);
+    assert_eq!(ATOMIC.fetch_and(false, AcqRel), true);
+    assert_eq!(ATOMIC.fetch_or(true, SeqCst), false);
+    assert_eq!(ATOMIC.fetch_and(false, SeqCst), true);
+    assert_eq!(ATOMIC.load(Relaxed), false);
+}
+
+#[test]
+fn atomic_nand() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicU8 = AtomicU8::new(0x13);
+
+    assert_eq!(ATOMIC.fetch_nand(0x13, Relaxed), 0x13);
+    assert_eq!(ATOMIC.fetch_nand(0xec, Acquire), 0xec);
+    assert_eq!(ATOMIC.fetch_nand(0x13, Release), 0x13);
+    assert_eq!(ATOMIC.fetch_nand(0xec, AcqRel), 0xec);
+    assert_eq!(ATOMIC.fetch_nand(0x13, SeqCst), 0x13);
+    assert_eq!(ATOMIC.load(Relaxed), 0xec);
+}
+
+#[test]
+fn atomic_xor() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicBool = AtomicBool::new(false);
+
+    assert_eq!(ATOMIC.fetch_xor(true, Relaxed), false);
+    assert_eq!(ATOMIC.fetch_xor(true, Acquire), true);
+    assert_eq!(ATOMIC.fetch_xor(true, Release), false);
+    assert_eq!(ATOMIC.fetch_xor(true, AcqRel), true);
+    assert_eq!(ATOMIC.fetch_xor(true, SeqCst), false);
+    assert_eq!(ATOMIC.load(Relaxed), true);
+}
+
+#[test]
+fn atomic_max() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicI8 = AtomicI8::new(0);
+
+    assert_eq!(ATOMIC.fetch_max(1, Relaxed), 0);
+    assert_eq!(ATOMIC.fetch_max(2, Acquire), 1);
+    assert_eq!(ATOMIC.fetch_max(3, Release), 2);
+    assert_eq!(ATOMIC.fetch_max(4, AcqRel), 3);
+    assert_eq!(ATOMIC.fetch_max(5, SeqCst), 4);
+    assert_eq!(ATOMIC.load(Relaxed), 5);
+}
+
+#[test]
+fn atomic_umax() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicU8 = AtomicU8::new(0);
+
+    assert_eq!(ATOMIC.fetch_max(1, Relaxed), 0);
+    assert_eq!(ATOMIC.fetch_max(2, Acquire), 1);
+    assert_eq!(ATOMIC.fetch_max(3, Release), 2);
+    assert_eq!(ATOMIC.fetch_max(4, AcqRel), 3);
+    assert_eq!(ATOMIC.fetch_max(5, SeqCst), 4);
+    assert_eq!(ATOMIC.load(Relaxed), 5);
+}
+
+#[test]
+fn atomic_min() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicI8 = AtomicI8::new(5);
+
+    assert_eq!(ATOMIC.fetch_min(4, Relaxed), 5);
+    assert_eq!(ATOMIC.fetch_min(3, Acquire), 4);
+    assert_eq!(ATOMIC.fetch_min(2, Release), 3);
+    assert_eq!(ATOMIC.fetch_min(1, AcqRel), 2);
+    assert_eq!(ATOMIC.fetch_min(0, SeqCst), 1);
+    assert_eq!(ATOMIC.load(Relaxed), 0);
+}
+
+#[test]
+fn atomic_umin() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicU8 = AtomicU8::new(5);
+
+    assert_eq!(ATOMIC.fetch_min(4, Relaxed), 5);
+    assert_eq!(ATOMIC.fetch_min(3, Acquire), 4);
+    assert_eq!(ATOMIC.fetch_min(2, Release), 3);
+    assert_eq!(ATOMIC.fetch_min(1, AcqRel), 2);
+    assert_eq!(ATOMIC.fetch_min(0, SeqCst), 1);
+    assert_eq!(ATOMIC.load(Relaxed), 0);
+}
+
 /* FIXME(#110395)
 #[test]
 fn atomic_const_from() {
diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs
index d31eba863f5..62278bf96c3 100644
--- a/library/coretests/tests/floats/f128.rs
+++ b/library/coretests/tests/floats/f128.rs
@@ -21,24 +21,6 @@ const TOL_PRECISE: f128 = 1e-28;
 // the intrinsics.
 
 #[test]
-#[cfg(not(miri))]
-#[cfg(target_has_reliable_f128_math)]
-fn test_mul_add() {
-    let nan: f128 = f128::NAN;
-    let inf: f128 = f128::INFINITY;
-    let neg_inf: f128 = f128::NEG_INFINITY;
-    assert_biteq!(12.3f128.mul_add(4.5, 6.7), 62.0500000000000000000000000000000037);
-    assert_biteq!((-12.3f128).mul_add(-4.5, -6.7), 48.6500000000000000000000000000000049);
-    assert_biteq!(0.0f128.mul_add(8.9, 1.2), 1.2);
-    assert_biteq!(3.4f128.mul_add(-0.0, 5.6), 5.6);
-    assert!(nan.mul_add(7.8, 9.0).is_nan());
-    assert_biteq!(inf.mul_add(7.8, 9.0), inf);
-    assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
-    assert_biteq!(8.9f128.mul_add(inf, 3.2), inf);
-    assert_biteq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf);
-}
-
-#[test]
 #[cfg(any(miri, target_has_reliable_f128_math))]
 fn test_max_recip() {
     assert_approx_eq!(
diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs
index 302fd0861d7..7ffafd467a5 100644
--- a/library/coretests/tests/floats/f16.rs
+++ b/library/coretests/tests/floats/f16.rs
@@ -23,24 +23,6 @@ const TOL_P4: f16 = 10.0;
 // the intrinsics.
 
 #[test]
-#[cfg(not(miri))]
-#[cfg(target_has_reliable_f16_math)]
-fn test_mul_add() {
-    let nan: f16 = f16::NAN;
-    let inf: f16 = f16::INFINITY;
-    let neg_inf: f16 = f16::NEG_INFINITY;
-    assert_biteq!(12.3f16.mul_add(4.5, 6.7), 62.031);
-    assert_biteq!((-12.3f16).mul_add(-4.5, -6.7), 48.625);
-    assert_biteq!(0.0f16.mul_add(8.9, 1.2), 1.2);
-    assert_biteq!(3.4f16.mul_add(-0.0, 5.6), 5.6);
-    assert!(nan.mul_add(7.8, 9.0).is_nan());
-    assert_biteq!(inf.mul_add(7.8, 9.0), inf);
-    assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
-    assert_biteq!(8.9f16.mul_add(inf, 3.2), inf);
-    assert_biteq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf);
-}
-
-#[test]
 #[cfg(any(miri, target_has_reliable_f16_math))]
 fn test_max_recip() {
     assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4);
diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs
deleted file mode 100644
index a1fe8b07650..00000000000
--- a/library/coretests/tests/floats/f32.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use core::f32;
-
-use super::assert_biteq;
-
-// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
-#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)]
-#[test]
-fn test_mul_add() {
-    let nan: f32 = f32::NAN;
-    let inf: f32 = f32::INFINITY;
-    let neg_inf: f32 = f32::NEG_INFINITY;
-    assert_biteq!(f32::math::mul_add(12.3f32, 4.5, 6.7), 62.05);
-    assert_biteq!(f32::math::mul_add(-12.3f32, -4.5, -6.7), 48.65);
-    assert_biteq!(f32::math::mul_add(0.0f32, 8.9, 1.2), 1.2);
-    assert_biteq!(f32::math::mul_add(3.4f32, -0.0, 5.6), 5.6);
-    assert!(f32::math::mul_add(nan, 7.8, 9.0).is_nan());
-    assert_biteq!(f32::math::mul_add(inf, 7.8, 9.0), inf);
-    assert_biteq!(f32::math::mul_add(neg_inf, 7.8, 9.0), neg_inf);
-    assert_biteq!(f32::math::mul_add(8.9f32, inf, 3.2), inf);
-    assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf);
-}
diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs
deleted file mode 100644
index 4c5a3d68d1f..00000000000
--- a/library/coretests/tests/floats/f64.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use core::f64;
-
-use super::assert_biteq;
-
-// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
-#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)]
-#[test]
-fn test_mul_add() {
-    let nan: f64 = f64::NAN;
-    let inf: f64 = f64::INFINITY;
-    let neg_inf: f64 = f64::NEG_INFINITY;
-    assert_biteq!(12.3f64.mul_add(4.5, 6.7), 62.050000000000004);
-    assert_biteq!((-12.3f64).mul_add(-4.5, -6.7), 48.650000000000006);
-    assert_biteq!(0.0f64.mul_add(8.9, 1.2), 1.2);
-    assert_biteq!(3.4f64.mul_add(-0.0, 5.6), 5.6);
-    assert!(nan.mul_add(7.8, 9.0).is_nan());
-    assert_biteq!(inf.mul_add(7.8, 9.0), inf);
-    assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
-    assert_biteq!(8.9f64.mul_add(inf, 3.2), inf);
-    assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf);
-}
diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs
index 31515561c63..0348065d17f 100644
--- a/library/coretests/tests/floats/mod.rs
+++ b/library/coretests/tests/floats/mod.rs
@@ -34,6 +34,10 @@ trait TestableFloat: Sized {
     const RAW_12_DOT_5: Self;
     const RAW_1337: Self;
     const RAW_MINUS_14_DOT_25: Self;
+    /// The result of 12.3.mul_add(4.5, 6.7)
+    const MUL_ADD_RESULT: Self;
+    /// The result of (-12.3).mul_add(-4.5, -6.7)
+    const NEG_MUL_ADD_RESULT: Self;
 }
 
 impl TestableFloat for f16 {
@@ -58,6 +62,8 @@ impl TestableFloat for f16 {
     const RAW_12_DOT_5: Self = Self::from_bits(0x4a40);
     const RAW_1337: Self = Self::from_bits(0x6539);
     const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xcb20);
+    const MUL_ADD_RESULT: Self = 62.031;
+    const NEG_MUL_ADD_RESULT: Self = 48.625;
 }
 
 impl TestableFloat for f32 {
@@ -84,6 +90,8 @@ impl TestableFloat for f32 {
     const RAW_12_DOT_5: Self = Self::from_bits(0x41480000);
     const RAW_1337: Self = Self::from_bits(0x44a72000);
     const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc1640000);
+    const MUL_ADD_RESULT: Self = 62.05;
+    const NEG_MUL_ADD_RESULT: Self = 48.65;
 }
 
 impl TestableFloat for f64 {
@@ -106,6 +114,8 @@ impl TestableFloat for f64 {
     const RAW_12_DOT_5: Self = Self::from_bits(0x4029000000000000);
     const RAW_1337: Self = Self::from_bits(0x4094e40000000000);
     const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc02c800000000000);
+    const MUL_ADD_RESULT: Self = 62.050000000000004;
+    const NEG_MUL_ADD_RESULT: Self = 48.650000000000006;
 }
 
 impl TestableFloat for f128 {
@@ -128,6 +138,8 @@ impl TestableFloat for f128 {
     const RAW_12_DOT_5: Self = Self::from_bits(0x40029000000000000000000000000000);
     const RAW_1337: Self = Self::from_bits(0x40094e40000000000000000000000000);
     const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc002c800000000000000000000000000);
+    const MUL_ADD_RESULT: Self = 62.0500000000000000000000000000000037;
+    const NEG_MUL_ADD_RESULT: Self = 48.6500000000000000000000000000000049;
 }
 
 /// Determine the tolerance for values of the argument type.
@@ -359,8 +371,6 @@ macro_rules! float_test {
 
 mod f128;
 mod f16;
-mod f32;
-mod f64;
 
 float_test! {
     name: num,
@@ -1180,15 +1190,12 @@ float_test! {
     }
 }
 
-// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
-// the intrinsics.
-
 float_test! {
     name: sqrt_domain,
     attrs: {
         const: #[cfg(false)],
-        f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
-        f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
+        f16: #[cfg(any(miri, target_has_reliable_f16_math))],
+        f128: #[cfg(any(miri, target_has_reliable_f128_math))],
     },
     test<Float> {
         assert!(Float::NAN.sqrt().is_nan());
@@ -1246,104 +1253,103 @@ float_test! {
 float_test! {
     name: total_cmp,
     attrs: {
-        const: #[cfg(false)],
-        f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
-        f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
+        f16: #[cfg(any(miri, target_has_reliable_f16_math))],
+        f128: #[cfg(any(miri, target_has_reliable_f128_math))],
     },
     test<Float> {
         use core::cmp::Ordering;
 
-        fn quiet_bit_mask() -> <Float as TestableFloat>::Int {
+        const fn quiet_bit_mask() -> <Float as TestableFloat>::Int {
             1 << (Float::MANTISSA_DIGITS - 2)
         }
 
-        fn q_nan() -> Float {
+        const fn q_nan() -> Float {
             Float::from_bits(Float::NAN.to_bits() | quiet_bit_mask())
         }
 
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-q_nan(), &-q_nan()));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::INFINITY, &-Float::INFINITY));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::MAX, &-Float::MAX));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-2.5, &-2.5));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-1.0, &-1.0));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-1.5, &-1.5));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-0.5, &-0.5));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-Float::TINY, &-Float::TINY));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&-0.0, &-0.0));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&0.0, &0.0));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&Float::TINY, &Float::TINY));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&Float::MIN_POSITIVE, &Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&0.5, &0.5));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&1.0, &1.0));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&1.5, &1.5));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&2.5, &2.5));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&Float::MAX, &Float::MAX));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&Float::INFINITY, &Float::INFINITY));
-        assert_eq!(Ordering::Equal, Float::total_cmp(&q_nan(), &q_nan()));
-
-        assert_eq!(Ordering::Less, Float::total_cmp(&-Float::INFINITY, &-Float::MAX));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-Float::MAX, &-2.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-2.5, &-1.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-1.5, &-1.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-1.0, &-0.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-0.5, &-Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::TINY));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-Float::TINY, &-0.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-0.0, &0.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&0.0, &Float::TINY));
-        assert_eq!(Ordering::Less, Float::total_cmp(&Float::TINY, &Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Less, Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, Float::total_cmp(&Float::MIN_POSITIVE, &0.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&0.5, &1.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&1.0, &1.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&1.5, &2.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&2.5, &Float::MAX));
-        assert_eq!(Ordering::Less, Float::total_cmp(&Float::MAX, &Float::INFINITY));
-
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::MAX, &-Float::INFINITY));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-2.5, &-Float::MAX));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-1.5, &-2.5));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-1.0, &-1.5));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-0.5, &-1.0));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::MIN_POSITIVE, &-0.5));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-Float::TINY, &-Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&-0.0, &-Float::TINY));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&0.0, &-0.0));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&Float::TINY, &0.0));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::TINY));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&Float::MIN_POSITIVE, &Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&0.5, &Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&1.0, &0.5));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&1.5, &1.0));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&2.5, &1.5));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&Float::MAX, &2.5));
-        assert_eq!(Ordering::Greater, Float::total_cmp(&Float::INFINITY, &Float::MAX));
-
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::INFINITY));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::MAX));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-2.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-1.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-1.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-0.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-Float::TINY));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &-0.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &0.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::TINY));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::MAX_SUBNORMAL));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::MIN_POSITIVE));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &0.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &1.0));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &1.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &2.5));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::MAX));
-        assert_eq!(Ordering::Less, Float::total_cmp(&-q_nan(), &Float::INFINITY));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-q_nan()), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-Float::INFINITY, &-Float::INFINITY), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-Float::MAX, &-Float::MAX), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-2.5, &-2.5), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-1.0, &-1.0), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-1.5, &-1.5), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-0.5, &-0.5), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MIN_POSITIVE), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MAX_SUBNORMAL), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-Float::TINY, &-Float::TINY), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&-0.0, &-0.0), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&0.0, &0.0), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&Float::TINY, &Float::TINY), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MAX_SUBNORMAL), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&Float::MIN_POSITIVE, &Float::MIN_POSITIVE), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&0.5, &0.5), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&1.0, &1.0), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&1.5, &1.5), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&2.5, &2.5), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&Float::MAX, &Float::MAX), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&Float::INFINITY, &Float::INFINITY), Ordering::Equal));
+        assert!(matches!(Float::total_cmp(&q_nan(), &q_nan()), Ordering::Equal));
+
+        assert!(matches!(Float::total_cmp(&-Float::INFINITY, &-Float::MAX), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-Float::MAX, &-2.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-2.5, &-1.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-1.5, &-1.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-1.0, &-0.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-0.5, &-Float::MIN_POSITIVE), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-Float::MIN_POSITIVE, &-Float::MAX_SUBNORMAL), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::TINY), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-Float::TINY, &-0.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-0.0, &0.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&0.0, &Float::TINY), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&Float::TINY, &Float::MAX_SUBNORMAL), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::MIN_POSITIVE), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&Float::MIN_POSITIVE, &0.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&0.5, &1.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&1.0, &1.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&1.5, &2.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&2.5, &Float::MAX), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&Float::MAX, &Float::INFINITY), Ordering::Less));
+
+        assert!(matches!(Float::total_cmp(&-Float::MAX, &-Float::INFINITY), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-2.5, &-Float::MAX), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-1.5, &-2.5), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-1.0, &-1.5), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-0.5, &-1.0), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-Float::MIN_POSITIVE, &-0.5), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-Float::MAX_SUBNORMAL, &-Float::MIN_POSITIVE), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-Float::TINY, &-Float::MAX_SUBNORMAL), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&-0.0, &-Float::TINY), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&0.0, &-0.0), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&Float::TINY, &0.0), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&Float::MAX_SUBNORMAL, &Float::TINY), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&Float::MIN_POSITIVE, &Float::MAX_SUBNORMAL), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&0.5, &Float::MIN_POSITIVE), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&1.0, &0.5), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&1.5, &1.0), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&2.5, &1.5), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&Float::MAX, &2.5), Ordering::Greater));
+        assert!(matches!(Float::total_cmp(&Float::INFINITY, &Float::MAX), Ordering::Greater));
+
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::INFINITY), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::MAX), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-2.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-1.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-1.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-0.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::MIN_POSITIVE), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::MAX_SUBNORMAL), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-Float::TINY), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &-0.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &0.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &Float::TINY), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &Float::MAX_SUBNORMAL), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &Float::MIN_POSITIVE), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &0.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &1.0), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &1.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &2.5), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &Float::MAX), Ordering::Less));
+        assert!(matches!(Float::total_cmp(&-q_nan(), &Float::INFINITY), Ordering::Less));
 
     }
 }
@@ -1356,8 +1362,8 @@ float_test! {
     name: total_cmp_s_nan,
     attrs: {
         const: #[cfg(false)],
-        f16: #[cfg(false)],
-        f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
+        f16: #[cfg(miri)],
+        f128: #[cfg(any(miri, target_has_reliable_f128_math))],
     },
     test<Float> {
         use core::cmp::Ordering;
@@ -1433,6 +1439,7 @@ float_test! {
     name: powi,
     attrs: {
         const: #[cfg(false)],
+        // FIXME(f16_f128): `powi` does not work in Miri for these types
         f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
         f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
     },
@@ -1453,8 +1460,8 @@ float_test! {
 float_test! {
     name: to_degrees,
     attrs: {
-        f16: #[cfg(target_has_reliable_f16)],
-        f128: #[cfg(target_has_reliable_f128)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
     },
     test<Float> {
         let pi: Float = Float::PI;
@@ -1474,8 +1481,8 @@ float_test! {
 float_test! {
     name: to_radians,
     attrs: {
-        f16: #[cfg(target_has_reliable_f16)],
-        f128: #[cfg(target_has_reliable_f128)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
     },
     test<Float> {
         let pi: Float = Float::PI;
@@ -1495,8 +1502,8 @@ float_test! {
 float_test! {
     name: to_algebraic,
     attrs: {
-        f16: #[cfg(target_has_reliable_f16)],
-        f128: #[cfg(target_has_reliable_f128)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
     },
     test<Float> {
         let a: Float = 123.0;
@@ -1519,8 +1526,8 @@ float_test! {
 float_test! {
     name: to_bits_conv,
     attrs: {
-        f16: #[cfg(target_has_reliable_f16)],
-        f128: #[cfg(target_has_reliable_f128)],
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
     },
     test<Float> {
         assert_biteq!(flt(1.0), Float::RAW_1);
@@ -1542,3 +1549,28 @@ float_test! {
         assert_biteq!(Float::from_bits(masked_nan2), Float::from_bits(masked_nan2));
     }
 }
+
+float_test! {
+    name: mul_add,
+    attrs: {
+        f16: #[cfg(any(miri, target_has_reliable_f16))],
+        // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
+        f32: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)],
+        f64: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)],
+        f128: #[cfg(any(miri, target_has_reliable_f128))],
+    },
+    test<Float> {
+        let nan: Float = Float::NAN;
+        let inf: Float = Float::INFINITY;
+        let neg_inf: Float = Float::NEG_INFINITY;
+        assert_biteq!(flt(12.3).mul_add(4.5, 6.7), Float::MUL_ADD_RESULT);
+        assert_biteq!((flt(-12.3)).mul_add(-4.5, -6.7), Float::NEG_MUL_ADD_RESULT);
+        assert_biteq!(flt(0.0).mul_add(8.9, 1.2), 1.2);
+        assert_biteq!(flt(3.4).mul_add(-0.0, 5.6), 5.6);
+        assert!(nan.mul_add(7.8, 9.0).is_nan());
+        assert_biteq!(inf.mul_add(7.8, 9.0), inf);
+        assert_biteq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
+        assert_biteq!(flt(8.9).mul_add(inf, 3.2), inf);
+        assert_biteq!((flt(-3.2)).mul_add(2.4, neg_inf), neg_inf);
+    }
+}
diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs
index 586e890befe..d0ae7124f47 100644
--- a/library/coretests/tests/fmt/mod.rs
+++ b/library/coretests/tests/fmt/mod.rs
@@ -12,6 +12,12 @@ fn test_lifetime() {
     let a = format_args!("hello {a} {a:?}");
     assert_eq!(a.to_string(), "hello hello hello hello hello hello hello");
 
+    // Check that temporaries as arguments are extended.
+    let b = format_args!("{}", String::new());
+    let c = format_args!("{}{}", String::new(), String::new());
+    assert_eq!(b.to_string(), "");
+    assert_eq!(c.to_string(), "");
+
     // Without arguments, it should also work in consts.
     const A: std::fmt::Arguments<'static> = format_args!("hello");
     assert_eq!(A.to_string(), "hello");
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 5c519f3a499..a80d7f8b44d 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -20,6 +20,7 @@
 #![feature(const_convert)]
 #![feature(const_destruct)]
 #![feature(const_eval_select)]
+#![feature(const_mul_add)]
 #![feature(const_ops)]
 #![feature(const_option_ops)]
 #![feature(const_ref_cell)]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index d28a7f0b460..888914a2f77 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -62,7 +62,7 @@ path = "../windows_targets"
 rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
 rand_xorshift = "0.4.0"
 
-[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
+[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", target_os = "vexos", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
 dlmalloc = { version = "0.2.10", features = ['rustc-dep-of-std'] }
 
 [target.x86_64-fortanix-unknown-sgx.dependencies]
@@ -89,6 +89,11 @@ wasip2 = { version = '0.14.4', features = [
 r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] }
 r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] }
 
+[target.'cfg(target_os = "vexos")'.dependencies]
+vex-sdk = { version = "0.27.0", features = [
+    'rustc-dep-of-std',
+], default-features = false }
+
 [features]
 backtrace = [
     'addr2line/rustc-dep-of-std',
@@ -106,11 +111,6 @@ compiler-builtins-no-f16-f128 = ["alloc/compiler-builtins-no-f16-f128"]
 llvm-libunwind = ["unwind/llvm-libunwind"]
 system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
 
-# Make panics and failed asserts immediately abort without formatting any message
-panic_immediate_abort = [
-    "core/panic_immediate_abort",
-    "alloc/panic_immediate_abort",
-]
 # Choose algorithms that are optimized for binary size instead of runtime performance
 optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]
 
diff --git a/library/std/build.rs b/library/std/build.rs
index ef695601a44..8a5a785060c 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -52,6 +52,7 @@ fn main() {
         || target_os == "rtems"
         || target_os == "nuttx"
         || target_os == "cygwin"
+        || target_os == "vexos"
 
         // See src/bootstrap/src/core/build_steps/synthetic_targets.rs
         || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index e457cd61c75..6d716bd8544 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -1098,6 +1098,7 @@ pub mod consts {
     /// * `"redox"`
     /// * `"solaris"`
     /// * `"solid_asp3`
+    /// * `"vexos"`
     /// * `"vita"`
     /// * `"vxworks"`
     /// * `"xous"`
@@ -1148,6 +1149,7 @@ pub mod consts {
     ///
     /// <details><summary>Full list of possible values</summary>
     ///
+    /// * `"bin"`
     /// * `"exe"`
     /// * `"efi"`
     /// * `"js"`
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index ff0e29e04c2..a45edd08e8c 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1081,7 +1081,7 @@ pub trait Read {
         default_read_buf_exact(self, cursor)
     }
 
-    /// Creates a "by reference" adaptor for this instance of `Read`.
+    /// Creates a "by reference" adapter for this instance of `Read`.
     ///
     /// The returned adapter also implements `Read` and will simply borrow this
     /// current reader.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 45abd6bca8a..233e41aa345 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -332,6 +332,7 @@
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
 #![feature(const_convert)]
+#![feature(const_mul_add)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
 #![feature(drop_guard)]
diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs
index 5b56dd3f744..8214ad381f1 100644
--- a/library/std/src/net/socket_addr.rs
+++ b/library/std/src/net/socket_addr.rs
@@ -28,6 +28,8 @@ use crate::{io, iter, option, slice, vec};
 ///    [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like
 ///    `<host_name>:<port>` pair where `<port>` is a [`u16`] value.
 ///
+///  * <code>&[[SocketAddr]]</code>: all [`SocketAddr`] values in the slice will be used.
+///
 /// This trait allows constructing network objects like [`TcpStream`] or
 /// [`UdpSocket`] easily with values of various types for the bind/connection
 /// address. It is needed because sometimes one type is more appropriate than
diff --git a/library/std/src/num/f128.rs b/library/std/src/num/f128.rs
index b83692390b6..5d206c4b7da 100644
--- a/library/std/src/num/f128.rs
+++ b/library/std/src/num/f128.rs
@@ -44,7 +44,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn powf(self, n: f128) -> f128 {
-        unsafe { intrinsics::powf128(self, n) }
+        intrinsics::powf128(self, n)
     }
 
     /// Returns `e^(self)`, (the exponential function).
@@ -76,7 +76,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn exp(self) -> f128 {
-        unsafe { intrinsics::expf128(self) }
+        intrinsics::expf128(self)
     }
 
     /// Returns `2^(self)`.
@@ -106,7 +106,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn exp2(self) -> f128 {
-        unsafe { intrinsics::exp2f128(self) }
+        intrinsics::exp2f128(self)
     }
 
     /// Returns the natural logarithm of the number.
@@ -151,7 +151,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn ln(self) -> f128 {
-        unsafe { intrinsics::logf128(self) }
+        intrinsics::logf128(self)
     }
 
     /// Returns the logarithm of the number with respect to an arbitrary base.
@@ -241,7 +241,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn log2(self) -> f128 {
-        unsafe { intrinsics::log2f128(self) }
+        intrinsics::log2f128(self)
     }
 
     /// Returns the base 10 logarithm of the number.
@@ -284,7 +284,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn log10(self) -> f128 {
-        unsafe { intrinsics::log10f128(self) }
+        intrinsics::log10f128(self)
     }
 
     /// Returns the cube root of a number.
@@ -385,7 +385,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sin(self) -> f128 {
-        unsafe { intrinsics::sinf128(self) }
+        intrinsics::sinf128(self)
     }
 
     /// Computes the cosine of a number (in radians).
@@ -414,7 +414,7 @@ impl f128 {
     #[unstable(feature = "f128", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn cos(self) -> f128 {
-        unsafe { intrinsics::cosf128(self) }
+        intrinsics::cosf128(self)
     }
 
     /// Computes the tangent of a number (in radians).
diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs
index 5599528717c..2565ef0f9f2 100644
--- a/library/std/src/num/f16.rs
+++ b/library/std/src/num/f16.rs
@@ -44,7 +44,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn powf(self, n: f16) -> f16 {
-        unsafe { intrinsics::powf16(self, n) }
+        intrinsics::powf16(self, n)
     }
 
     /// Returns `e^(self)`, (the exponential function).
@@ -76,7 +76,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn exp(self) -> f16 {
-        unsafe { intrinsics::expf16(self) }
+        intrinsics::expf16(self)
     }
 
     /// Returns `2^(self)`.
@@ -106,7 +106,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn exp2(self) -> f16 {
-        unsafe { intrinsics::exp2f16(self) }
+        intrinsics::exp2f16(self)
     }
 
     /// Returns the natural logarithm of the number.
@@ -151,7 +151,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn ln(self) -> f16 {
-        unsafe { intrinsics::logf16(self) }
+        intrinsics::logf16(self)
     }
 
     /// Returns the logarithm of the number with respect to an arbitrary base.
@@ -241,7 +241,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn log2(self) -> f16 {
-        unsafe { intrinsics::log2f16(self) }
+        intrinsics::log2f16(self)
     }
 
     /// Returns the base 10 logarithm of the number.
@@ -284,7 +284,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn log10(self) -> f16 {
-        unsafe { intrinsics::log10f16(self) }
+        intrinsics::log10f16(self)
     }
 
     /// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -350,7 +350,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn sin(self) -> f16 {
-        unsafe { intrinsics::sinf16(self) }
+        intrinsics::sinf16(self)
     }
 
     /// Computes the cosine of a number (in radians).
@@ -379,7 +379,7 @@ impl f16 {
     #[unstable(feature = "f16", issue = "116909")]
     #[must_use = "method returns a new number and does not mutate the original value"]
     pub fn cos(self) -> f16 {
-        unsafe { intrinsics::cosf16(self) }
+        intrinsics::cosf16(self)
     }
 
     /// Computes the tangent of a number (in radians).
diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs
index 0247080a8d6..e7810e77e76 100644
--- a/library/std/src/num/f32.rs
+++ b/library/std/src/num/f32.rs
@@ -217,7 +217,8 @@ impl f32 {
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn mul_add(self, a: f32, b: f32) -> f32 {
+    #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")]
+    pub const fn mul_add(self, a: f32, b: f32) -> f32 {
         core::f32::math::mul_add(self, a, b)
     }
 
@@ -338,7 +339,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn powf(self, n: f32) -> f32 {
-        unsafe { intrinsics::powf32(self, n) }
+        intrinsics::powf32(self, n)
     }
 
     /// Returns the square root of a number.
@@ -395,7 +396,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn exp(self) -> f32 {
-        unsafe { intrinsics::expf32(self) }
+        intrinsics::expf32(self)
     }
 
     /// Returns `2^(self)`.
@@ -420,7 +421,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn exp2(self) -> f32 {
-        unsafe { intrinsics::exp2f32(self) }
+        intrinsics::exp2f32(self)
     }
 
     /// Returns the natural logarithm of the number.
@@ -455,7 +456,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ln(self) -> f32 {
-        unsafe { intrinsics::logf32(self) }
+        intrinsics::logf32(self)
     }
 
     /// Returns the logarithm of the number with respect to an arbitrary base.
@@ -525,7 +526,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn log2(self) -> f32 {
-        unsafe { intrinsics::log2f32(self) }
+        intrinsics::log2f32(self)
     }
 
     /// Returns the base 10 logarithm of the number.
@@ -558,7 +559,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn log10(self) -> f32 {
-        unsafe { intrinsics::log10f32(self) }
+        intrinsics::log10f32(self)
     }
 
     /// The positive difference of two numbers.
@@ -683,7 +684,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sin(self) -> f32 {
-        unsafe { intrinsics::sinf32(self) }
+        intrinsics::sinf32(self)
     }
 
     /// Computes the cosine of a number (in radians).
@@ -707,7 +708,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cos(self) -> f32 {
-        unsafe { intrinsics::cosf32(self) }
+        intrinsics::cosf32(self)
     }
 
     /// Computes the tangent of a number (in radians).
diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs
index 1cfd3909d96..cbebbfb1be1 100644
--- a/library/std/src/num/f64.rs
+++ b/library/std/src/num/f64.rs
@@ -217,7 +217,8 @@ impl f64 {
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn mul_add(self, a: f64, b: f64) -> f64 {
+    #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")]
+    pub const fn mul_add(self, a: f64, b: f64) -> f64 {
         core::f64::math::mul_add(self, a, b)
     }
 
@@ -338,7 +339,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn powf(self, n: f64) -> f64 {
-        unsafe { intrinsics::powf64(self, n) }
+        intrinsics::powf64(self, n)
     }
 
     /// Returns the square root of a number.
@@ -395,7 +396,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn exp(self) -> f64 {
-        unsafe { intrinsics::expf64(self) }
+        intrinsics::expf64(self)
     }
 
     /// Returns `2^(self)`.
@@ -420,7 +421,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn exp2(self) -> f64 {
-        unsafe { intrinsics::exp2f64(self) }
+        intrinsics::exp2f64(self)
     }
 
     /// Returns the natural logarithm of the number.
@@ -455,7 +456,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn ln(self) -> f64 {
-        unsafe { intrinsics::logf64(self) }
+        intrinsics::logf64(self)
     }
 
     /// Returns the logarithm of the number with respect to an arbitrary base.
@@ -525,7 +526,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn log2(self) -> f64 {
-        unsafe { intrinsics::log2f64(self) }
+        intrinsics::log2f64(self)
     }
 
     /// Returns the base 10 logarithm of the number.
@@ -558,7 +559,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn log10(self) -> f64 {
-        unsafe { intrinsics::log10f64(self) }
+        intrinsics::log10f64(self)
     }
 
     /// The positive difference of two numbers.
@@ -683,7 +684,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sin(self) -> f64 {
-        unsafe { intrinsics::sinf64(self) }
+        intrinsics::sinf64(self)
     }
 
     /// Computes the cosine of a number (in radians).
@@ -707,7 +708,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn cos(self) -> f64 {
-        unsafe { intrinsics::cosf64(self) }
+        intrinsics::cosf64(self)
     }
 
     /// Computes the tangent of a number (in radians).
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 8b7282c51d1..b7be869c4eb 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -331,7 +331,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
 
 #[cfg(not(test))]
 #[doc(hidden)]
-#[cfg(feature = "panic_immediate_abort")]
+#[cfg(panic = "immediate-abort")]
 #[unstable(feature = "update_panic_count", issue = "none")]
 pub mod panic_count {
     /// A reason for forcing an immediate abort on panic.
@@ -371,7 +371,7 @@ pub mod panic_count {
 
 #[cfg(not(test))]
 #[doc(hidden)]
-#[cfg(not(feature = "panic_immediate_abort"))]
+#[cfg(not(panic = "immediate-abort"))]
 #[unstable(feature = "update_panic_count", issue = "none")]
 pub mod panic_count {
     use crate::cell::Cell;
@@ -499,13 +499,13 @@ pub mod panic_count {
 pub use realstd::rt::panic_count;
 
 /// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
-#[cfg(feature = "panic_immediate_abort")]
+#[cfg(panic = "immediate-abort")]
 pub unsafe fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
     Ok(f())
 }
 
 /// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
-#[cfg(not(feature = "panic_immediate_abort"))]
+#[cfg(not(panic = "immediate-abort"))]
 pub unsafe fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
     union Data<F, R> {
         f: ManuallyDrop<F>,
@@ -720,14 +720,14 @@ pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
 #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")]
 #[cfg_attr(not(any(test, doctest)), lang = "begin_panic")]
 // lang item for CTFE panic support
-// never inline unless panic_immediate_abort to avoid code
+// never inline unless panic=immediate-abort to avoid code
 // bloat at the call sites as much as possible
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
+#[cfg_attr(panic = "immediate-abort", inline)]
 #[track_caller]
 #[rustc_do_not_const_check] // hooked by const-eval
 pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
-    if cfg!(feature = "panic_immediate_abort") {
+    if cfg!(panic = "immediate-abort") {
         intrinsics::abort()
     }
 
@@ -861,7 +861,7 @@ fn panic_with_hook(
 
 /// This is the entry point for `resume_unwind`.
 /// It just forwards the payload to the panic runtime.
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(panic = "immediate-abort", inline)]
 pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
     panic_count::increase(false);
 
@@ -890,16 +890,14 @@ pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
 /// on which to slap yer breakpoints.
 #[inline(never)]
 #[cfg_attr(not(test), rustc_std_internal_symbol)]
-#[cfg(not(feature = "panic_immediate_abort"))]
+#[cfg(not(panic = "immediate-abort"))]
 fn rust_panic(msg: &mut dyn PanicPayload) -> ! {
     let code = unsafe { __rust_start_panic(msg) };
     rtabort!("failed to initiate panic, error {code}")
 }
 
 #[cfg_attr(not(test), rustc_std_internal_symbol)]
-#[cfg(feature = "panic_immediate_abort")]
+#[cfg(panic = "immediate-abort")]
 fn rust_panic(_: &mut dyn PanicPayload) -> ! {
-    unsafe {
-        crate::intrinsics::abort();
-    }
+    crate::intrinsics::abort();
 }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 70ba502d684..88d8a4f21ca 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2107,7 +2107,7 @@ impl PartialEq for PathBuf {
 impl cmp::PartialEq<str> for PathBuf {
     #[inline]
     fn eq(&self, other: &str) -> bool {
-        Path::eq(self, other)
+        self.as_path() == other
     }
 }
 
@@ -2115,7 +2115,7 @@ impl cmp::PartialEq<str> for PathBuf {
 impl cmp::PartialEq<PathBuf> for str {
     #[inline]
     fn eq(&self, other: &PathBuf) -> bool {
-        other == self
+        self == other.as_path()
     }
 }
 
@@ -2123,7 +2123,7 @@ impl cmp::PartialEq<PathBuf> for str {
 impl cmp::PartialEq<String> for PathBuf {
     #[inline]
     fn eq(&self, other: &String) -> bool {
-        **self == **other
+        self.as_path() == other.as_str()
     }
 }
 
@@ -2131,7 +2131,7 @@ impl cmp::PartialEq<String> for PathBuf {
 impl cmp::PartialEq<PathBuf> for String {
     #[inline]
     fn eq(&self, other: &PathBuf) -> bool {
-        other == self
+        self.as_str() == other.as_path()
     }
 }
 
@@ -3426,7 +3426,7 @@ impl cmp::PartialEq<Path> for str {
 impl cmp::PartialEq<String> for Path {
     #[inline]
     fn eq(&self, other: &String) -> bool {
-        self == &*other
+        self == other.as_str()
     }
 }
 
@@ -3434,7 +3434,7 @@ impl cmp::PartialEq<String> for Path {
 impl cmp::PartialEq<Path> for String {
     #[inline]
     fn eq(&self, other: &Path) -> bool {
-        other == self
+        self.as_str() == other
     }
 }
 
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 0883e56342c..5c0ac526a36 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -268,8 +268,8 @@ impl AsInner<imp::Process> for Child {
     }
 }
 
-impl FromInner<(imp::Process, imp::StdioPipes)> for Child {
-    fn from_inner((handle, io): (imp::Process, imp::StdioPipes)) -> Child {
+impl FromInner<(imp::Process, StdioPipes)> for Child {
+    fn from_inner((handle, io): (imp::Process, StdioPipes)) -> Child {
         Child {
             handle,
             stdin: io.stdin.map(ChildStdin::from_inner),
@@ -296,6 +296,15 @@ impl fmt::Debug for Child {
     }
 }
 
+/// The pipes connected to a spawned process.
+///
+/// Used to pass pipe handles between this module and [`imp`].
+pub(crate) struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
 /// A handle to a child process's standard input (stdin).
 ///
 /// This struct is used in the [`stdin`] field on [`Child`].
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 8d95cc1fb57..2717b7b469c 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -39,11 +39,11 @@ fn __rust_abort() {
 // - nothing (so this macro is a no-op)
 macro_rules! rtprintpanic {
     ($($t:tt)*) => {
-        #[cfg(not(feature = "panic_immediate_abort"))]
+        #[cfg(not(panic = "immediate-abort"))]
         if let Some(mut out) = crate::sys::stdio::panic_output() {
             let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
         }
-        #[cfg(feature = "panic_immediate_abort")]
+        #[cfg(panic = "immediate-abort")]
         {
             let _ = format_args!($($t)*);
         }
diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs
index 07430ce3a13..eeecf5d7107 100644
--- a/library/std/src/sync/nonpoison/mutex.rs
+++ b/library/std/src/sync/nonpoison/mutex.rs
@@ -373,7 +373,7 @@ impl<T: ?Sized> Mutex<T> {
     /// or written through after the mutex is dropped.
     #[unstable(feature = "mutex_data_ptr", issue = "140368")]
     // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
-    pub fn data_ptr(&self) -> *mut T {
+    pub const fn data_ptr(&self) -> *mut T {
         self.data.get()
     }
 }
diff --git a/library/std/src/sync/nonpoison/rwlock.rs b/library/std/src/sync/nonpoison/rwlock.rs
index eb0aef99cc1..b2f26edc083 100644
--- a/library/std/src/sync/nonpoison/rwlock.rs
+++ b/library/std/src/sync/nonpoison/rwlock.rs
@@ -495,7 +495,7 @@ impl<T: ?Sized> RwLock<T> {
     /// or written through after the lock is dropped.
     #[unstable(feature = "rwlock_data_ptr", issue = "140368")]
     // #[unstable(feature = "nonpoison_rwlock", issue = "134645")]
-    pub fn data_ptr(&self) -> *mut T {
+    pub const fn data_ptr(&self) -> *mut T {
         self.data.get()
     }
 }
diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs
index 7e9d920d92f..6fdb4f6799e 100644
--- a/library/std/src/sync/poison/mutex.rs
+++ b/library/std/src/sync/poison/mutex.rs
@@ -668,7 +668,7 @@ impl<T: ?Sized> Mutex<T> {
     /// are properly synchronized to avoid data races, and that it is not read
     /// or written through after the mutex is dropped.
     #[unstable(feature = "mutex_data_ptr", issue = "140368")]
-    pub fn data_ptr(&self) -> *mut T {
+    pub const fn data_ptr(&self) -> *mut T {
         self.data.get()
     }
 }
diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs
index 0a463f3f9c7..e3a72c73bf4 100644
--- a/library/std/src/sync/poison/rwlock.rs
+++ b/library/std/src/sync/poison/rwlock.rs
@@ -667,7 +667,7 @@ impl<T: ?Sized> RwLock<T> {
     /// are properly synchronized to avoid data races, and that it is not read
     /// or written through after the lock is dropped.
     #[unstable(feature = "rwlock_data_ptr", issue = "140368")]
-    pub fn data_ptr(&self) -> *mut T {
+    pub const fn data_ptr(&self) -> *mut T {
         self.data.get()
     }
 }
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index 4140718560c..f560b616dd9 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -355,7 +355,7 @@ impl<T: ?Sized> ReentrantLock<T> {
     /// properly synchronized to avoid data races, and that it is not read
     /// through after the lock is dropped.
     #[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")]
-    pub fn data_ptr(&self) -> *const T {
+    pub const fn data_ptr(&self) -> *const T {
         &raw const self.data
     }
 
diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs
index 6d4b09494a3..2045b2fecc6 100644
--- a/library/std/src/sys/alloc/mod.rs
+++ b/library/std/src/sys/alloc/mod.rs
@@ -92,6 +92,9 @@ cfg_select! {
     target_os = "uefi" => {
         mod uefi;
     }
+    target_os = "vexos" => {
+        mod vexos;
+    }
     target_family = "wasm" => {
         mod wasm;
     }
diff --git a/library/std/src/sys/alloc/vexos.rs b/library/std/src/sys/alloc/vexos.rs
new file mode 100644
index 00000000000..c1fb6896a89
--- /dev/null
+++ b/library/std/src/sys/alloc/vexos.rs
@@ -0,0 +1,96 @@
+// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
+#![allow(static_mut_refs)]
+
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+use crate::sync::atomic::{AtomicBool, Ordering};
+
+// Symbols for heap section boundaries defined in the target's linkerscript
+unsafe extern "C" {
+    static mut __heap_start: u8;
+    static mut __heap_end: u8;
+}
+
+static mut DLMALLOC: dlmalloc::Dlmalloc<Vexos> = dlmalloc::Dlmalloc::new_with_allocator(Vexos);
+
+struct Vexos;
+
+unsafe impl dlmalloc::Allocator for Vexos {
+    /// Allocs system resources
+    fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {
+        static INIT: AtomicBool = AtomicBool::new(false);
+
+        if !INIT.swap(true, Ordering::Relaxed) {
+            // This target has no growable heap, as user memory has a fixed
+            // size/location and VEXos does not manage allocation for us.
+            unsafe {
+                (
+                    (&raw mut __heap_start).cast::<u8>(),
+                    (&raw const __heap_end).offset_from_unsigned(&raw const __heap_start),
+                    0,
+                )
+            }
+        } else {
+            (ptr::null_mut(), 0, 0)
+        }
+    }
+
+    fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
+        ptr::null_mut()
+    }
+
+    fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
+        false
+    }
+
+    fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
+        return false;
+    }
+
+    fn can_release_part(&self, _flags: u32) -> bool {
+        false
+    }
+
+    fn allocates_zeros(&self) -> bool {
+        false
+    }
+
+    fn page_size(&self) -> usize {
+        0x1000
+    }
+}
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling malloc() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling calloc() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling free() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which
+        // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used.
+        // Calling realloc() is safe because preconditions on this function match the trait method preconditions.
+        unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
+    }
+}
diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs
index 711ba0a5f8a..573f540483b 100644
--- a/library/std/src/sys/env_consts.rs
+++ b/library/std/src/sys/env_consts.rs
@@ -323,6 +323,17 @@ pub mod os {
     pub const EXE_EXTENSION: &str = "efi";
 }
 
+#[cfg(target_os = "vexos")]
+pub mod os {
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "vexos";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = "";
+    pub const DLL_EXTENSION: &str = "";
+    pub const EXE_SUFFIX: &str = ".bin";
+    pub const EXE_EXTENSION: &str = "bin";
+}
+
 #[cfg(target_os = "visionos")]
 pub mod os {
     pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index 0276bf6e64c..64f5a6b36d3 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -35,6 +35,10 @@ cfg_select! {
         mod uefi;
         use uefi as imp;
     }
+    target_os = "vexos" => {
+        mod vexos;
+        use vexos as imp;
+    }
     target_os = "wasi" => {
         mod wasi;
         use wasi as imp;
diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs
new file mode 100644
index 00000000000..f642e7cb074
--- /dev/null
+++ b/library/std/src/sys/fs/vexos.rs
@@ -0,0 +1,615 @@
+use crate::ffi::{OsString, c_char};
+use crate::fmt;
+use crate::fs::TryLockError;
+use crate::hash::Hash;
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
+use crate::path::{Path, PathBuf};
+use crate::sys::common::small_c_string::run_path_with_cstr;
+use crate::sys::time::SystemTime;
+use crate::sys::{unsupported, unsupported_err};
+
+#[expect(dead_code)]
+#[path = "unsupported.rs"]
+mod unsupported_fs;
+pub use unsupported_fs::{
+    DirBuilder, FileTimes, canonicalize, link, readlink, remove_dir_all, rename, rmdir, symlink,
+    unlink,
+};
+
+/// VEXos file descriptor.
+///
+/// This stores an opaque pointer to a [FatFs file object structure] managed by VEXos
+/// representing an open file on disk.
+///
+/// [FatFs file object structure]: https://github.com/Xilinx/embeddedsw/blob/master/lib/sw_services/xilffs/src/include/ff.h?rgh-link-date=2025-09-23T20%3A03%3A43Z#L215
+///
+/// # Safety
+///
+/// Since this platform uses a pointer to to an internal filesystem structure with a lifetime
+/// associated with it (rather than a UNIX-style file descriptor table), care must be taken to
+/// ensure that the pointer held by `FileDesc` is valid for as long as it exists.
+#[derive(Debug)]
+struct FileDesc(*mut vex_sdk::FIL);
+
+// SAFETY: VEXos's FDs can be used on a thread other than the one they were created on.
+unsafe impl Send for FileDesc {}
+// SAFETY: We assume an environment without threads (i.e. no RTOS).
+// (If there were threads, it is possible that a mutex would be required.)
+unsafe impl Sync for FileDesc {}
+
+pub struct File {
+    fd: FileDesc,
+}
+
+#[derive(Clone)]
+pub enum FileAttr {
+    Dir,
+    File { size: u64 },
+}
+
+pub struct ReadDir(!);
+
+pub struct DirEntry {
+    path: PathBuf,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+    read: bool,
+    write: bool,
+    append: bool,
+    truncate: bool,
+    create: bool,
+    create_new: bool,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions {}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct FileType {
+    is_dir: bool,
+}
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        match self {
+            Self::File { size } => *size,
+            Self::Dir => 0,
+        }
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        FilePermissions {}
+    }
+
+    pub fn file_type(&self) -> FileType {
+        FileType { is_dir: matches!(self, FileAttr::Dir) }
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        unsupported()
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        unsupported()
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        unsupported()
+    }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        false
+    }
+
+    pub fn set_readonly(&mut self, _readonly: bool) {
+        panic!("Perimissions do not exist")
+    }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        self.is_dir
+    }
+
+    pub fn is_file(&self) -> bool {
+        !self.is_dir
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        // No symlinks in VEXos - entries are either files or directories.
+        false
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        self.0
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        self.path.clone()
+    }
+
+    pub fn file_name(&self) -> OsString {
+        self.path.file_name().unwrap_or_default().into()
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        stat(&self.path)
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        Ok(self.metadata()?.file_type())
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {
+            read: false,
+            write: false,
+            append: false,
+            truncate: false,
+            create: false,
+            create_new: false,
+        }
+    }
+
+    pub fn read(&mut self, read: bool) {
+        self.read = read;
+    }
+    pub fn write(&mut self, write: bool) {
+        self.write = write;
+    }
+    pub fn append(&mut self, append: bool) {
+        self.append = append;
+    }
+    pub fn truncate(&mut self, truncate: bool) {
+        self.truncate = truncate;
+    }
+    pub fn create(&mut self, create: bool) {
+        self.create = create;
+    }
+    pub fn create_new(&mut self, create_new: bool) {
+        self.create_new = create_new;
+    }
+}
+
+impl File {
+    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+        run_path_with_cstr(path, &|path| {
+            // Enforce the invariants of `create_new`/`create`.
+            //
+            // Since VEXos doesn't have anything akin to POSIX's `oflags`, we need to enforce
+            // the requirements that `create_new` can't have an existing file and `!create`
+            // doesn't create a file ourselves.
+            if !opts.read && (opts.write || opts.append) && (opts.create_new || !opts.create) {
+                let status = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) };
+
+                if opts.create_new && status != 0 {
+                    return Err(io::const_error!(io::ErrorKind::AlreadyExists, "file exists",));
+                } else if !opts.create && status == 0 {
+                    return Err(io::const_error!(
+                        io::ErrorKind::NotFound,
+                        "no such file or directory",
+                    ));
+                }
+            }
+
+            let file = match opts {
+                // read + write - unsupported
+                OpenOptions { read: true, write: true, .. } => {
+                    return Err(io::const_error!(
+                        io::ErrorKind::InvalidInput,
+                        "opening files with read and write access is unsupported on this target",
+                    ));
+                }
+
+                // read
+                OpenOptions {
+                    read: true,
+                    write: false,
+                    append: _,
+                    truncate: false,
+                    create: false,
+                    create_new: false,
+                } => unsafe { vex_sdk::vexFileOpen(path.as_ptr(), c"".as_ptr()) },
+
+                // append
+                OpenOptions {
+                    read: false,
+                    write: _,
+                    append: true,
+                    truncate: false,
+                    create: _,
+                    create_new: _,
+                } => unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) },
+
+                // write
+                OpenOptions {
+                    read: false,
+                    write: true,
+                    append: false,
+                    truncate,
+                    create: _,
+                    create_new: _,
+                } => unsafe {
+                    if *truncate {
+                        vex_sdk::vexFileOpenCreate(path.as_ptr())
+                    } else {
+                        // Open in append, but jump to the start of the file.
+                        let fd = vex_sdk::vexFileOpenWrite(path.as_ptr());
+                        vex_sdk::vexFileSeek(fd, 0, 0);
+                        fd
+                    }
+                },
+
+                _ => {
+                    return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid argument"));
+                }
+            };
+
+            if file.is_null() {
+                Err(io::const_error!(io::ErrorKind::NotFound, "could not open file"))
+            } else {
+                Ok(Self { fd: FileDesc(file) })
+            }
+        })
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        // `vexFileSize` returns -1 upon error, so u64::try_from will fail on error.
+        if let Ok(size) = u64::try_from(unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileSize(self.fd.0)
+        }) {
+            Ok(FileAttr::File { size })
+        } else {
+            Err(io::const_error!(io::ErrorKind::InvalidData, "failed to get file size"))
+        }
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        self.flush()
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        self.flush()
+    }
+
+    pub fn lock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn try_lock(&self) -> Result<(), TryLockError> {
+        Err(TryLockError::Error(unsupported_err()))
+    }
+
+    pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
+        Err(TryLockError::Error(unsupported_err()))
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn truncate(&self, _size: u64) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let len = buf.len() as u32;
+        let buf_ptr = buf.as_mut_ptr();
+        let read = unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileRead(buf_ptr.cast::<c_char>(), 1, len, self.fd.0)
+        };
+
+        if read < 0 {
+            Err(io::const_error!(io::ErrorKind::Other, "could not read from file"))
+        } else {
+            Ok(read as usize)
+        }
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        crate::io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|b| self.read(b), cursor)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let len = buf.len() as u32;
+        let buf_ptr = buf.as_ptr();
+        let written = unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileWrite(buf_ptr.cast_mut().cast::<c_char>(), 1, len, self.fd.0)
+        };
+
+        if written < 0 {
+            Err(io::const_error!(io::ErrorKind::Other, "could not write to file"))
+        } else {
+            Ok(written as usize)
+        }
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        crate::io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        unsafe {
+            // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+            vex_sdk::vexFileSync(self.fd.0);
+        }
+        Ok(())
+    }
+
+    pub fn tell(&self) -> io::Result<u64> {
+        // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+        let position = unsafe { vex_sdk::vexFileTell(self.fd.0) };
+
+        position.try_into().map_err(|_| {
+            io::const_error!(io::ErrorKind::InvalidData, "failed to get current location in file")
+        })
+    }
+
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        None
+    }
+
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        const SEEK_SET: i32 = 0;
+        const SEEK_CUR: i32 = 1;
+        const SEEK_END: i32 = 2;
+
+        fn try_convert_offset<T: TryInto<u32>>(offset: T) -> io::Result<u32> {
+            offset.try_into().map_err(|_| {
+                io::const_error!(
+                    io::ErrorKind::InvalidInput,
+                    "cannot seek to an offset too large to fit in a 32 bit integer",
+                )
+            })
+        }
+
+        // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime.
+        match pos {
+            SeekFrom::Start(offset) => unsafe {
+                map_fresult(vex_sdk::vexFileSeek(self.fd.0, try_convert_offset(offset)?, SEEK_SET))?
+            },
+            SeekFrom::End(offset) => unsafe {
+                if offset >= 0 {
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        try_convert_offset(offset)?,
+                        SEEK_END,
+                    ))?
+                } else {
+                    // `vexFileSeek` does not support seeking with negative offset, meaning
+                    // we have to calculate the offset from the end of the file ourselves.
+
+                    // Seek to the end of the file to get the end position in the open buffer.
+                    map_fresult(vex_sdk::vexFileSeek(self.fd.0, 0, SEEK_END))?;
+                    let end_position = self.tell()?;
+
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        // NOTE: Files internally use a 32-bit representation for stream
+                        // position, so `end_position as i64` should never overflow.
+                        try_convert_offset(end_position as i64 + offset)?,
+                        SEEK_SET,
+                    ))?
+                }
+            },
+            SeekFrom::Current(offset) => unsafe {
+                if offset >= 0 {
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        try_convert_offset(offset)?,
+                        SEEK_CUR,
+                    ))?
+                } else {
+                    // `vexFileSeek` does not support seeking with negative offset, meaning
+                    // we have to calculate the offset from the stream position ourselves.
+                    map_fresult(vex_sdk::vexFileSeek(
+                        self.fd.0,
+                        try_convert_offset((self.tell()? as i64) + offset)?,
+                        SEEK_SET,
+                    ))?
+                }
+            },
+        }
+
+        Ok(self.tell()?)
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        unsupported()
+    }
+
+    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        unsupported()
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("File").field("fd", &self.fd.0).finish()
+    }
+}
+impl Drop for File {
+    fn drop(&mut self) {
+        unsafe { vex_sdk::vexFileClose(self.fd.0) };
+    }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+    // While there *is* a userspace function for reading file directories,
+    // the necessary implementation cannot currently be done cleanly, as
+    // VEXos does not expose directory length to user programs.
+    //
+    // This means that we would need to create a large fixed-length buffer
+    // and hope that the folder's contents didn't exceed that buffer's length,
+    // which obviously isn't behavior we want to rely on in the standard library.
+    unsupported()
+}
+
+pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn exists(path: &Path) -> io::Result<bool> {
+    run_path_with_cstr(path, &|path| Ok(unsafe { vex_sdk::vexFileStatus(path.as_ptr()) } != 0))
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+    // `vexFileStatus` returns 3 if the given path is a directory, 1 if the path is a
+    // file, or 0 if no such path exists.
+    const FILE_STATUS_DIR: u32 = 3;
+
+    run_path_with_cstr(p, &|c_path| {
+        let file_type = unsafe { vex_sdk::vexFileStatus(c_path.as_ptr()) };
+
+        // We can't get the size if its a directory because we cant open it as a file
+        if file_type == FILE_STATUS_DIR {
+            Ok(FileAttr::Dir)
+        } else {
+            let mut opts = OpenOptions::new();
+            opts.read(true);
+            let file = File::open(p, &opts)?;
+            file.file_attr()
+        }
+    })
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    // Symlinks aren't supported in this filesystem
+    stat(p)
+}
+
+// Cannot use `copy` from `common` here, since `File::set_permissions` is unsupported on this target.
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+    use crate::fs::File;
+
+    // NOTE: If `from` is a directory, this call should fail due to vexFileOpen* returning null.
+    let mut reader = File::open(from)?;
+    let mut writer = File::create(to)?;
+
+    io::copy(&mut reader, &mut writer)
+}
+
+fn map_fresult(fresult: vex_sdk::FRESULT) -> io::Result<()> {
+    // VEX uses a derivative of FatFs (Xilinx's xilffs library) for filesystem operations.
+    match fresult {
+        vex_sdk::FRESULT::FR_OK => Ok(()),
+        vex_sdk::FRESULT::FR_DISK_ERR => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "internal function reported an unrecoverable hard error",
+        )),
+        vex_sdk::FRESULT::FR_INT_ERR => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "internal error in filesystem runtime",
+        )),
+        vex_sdk::FRESULT::FR_NOT_READY => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "the storage device could not be prepared to work",
+        )),
+        vex_sdk::FRESULT::FR_NO_FILE => Err(io::const_error!(
+            io::ErrorKind::NotFound,
+            "could not find the file in the directory"
+        )),
+        vex_sdk::FRESULT::FR_NO_PATH => Err(io::const_error!(
+            io::ErrorKind::NotFound,
+            "a directory in the path name could not be found",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_NAME => Err(io::const_error!(
+            io::ErrorKind::InvalidInput,
+            "the given string is invalid as a path name",
+        )),
+        vex_sdk::FRESULT::FR_DENIED => Err(io::const_error!(
+            io::ErrorKind::PermissionDenied,
+            "the required access for this operation was denied",
+        )),
+        vex_sdk::FRESULT::FR_EXIST => Err(io::const_error!(
+            io::ErrorKind::AlreadyExists,
+            "an object with the same name already exists in the directory",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_OBJECT => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "invalid or null file/directory object",
+        )),
+        vex_sdk::FRESULT::FR_WRITE_PROTECTED => Err(io::const_error!(
+            io::ErrorKind::PermissionDenied,
+            "a write operation was performed on write-protected media",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_DRIVE => Err(io::const_error!(
+            io::ErrorKind::InvalidInput,
+            "an invalid drive number was specified in the path name",
+        )),
+        vex_sdk::FRESULT::FR_NOT_ENABLED => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "work area for the logical drive has not been registered",
+        )),
+        vex_sdk::FRESULT::FR_NO_FILESYSTEM => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "valid FAT volume could not be found on the drive",
+        )),
+        vex_sdk::FRESULT::FR_MKFS_ABORTED => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "failed to create filesystem volume"
+        )),
+        vex_sdk::FRESULT::FR_TIMEOUT => Err(io::const_error!(
+            io::ErrorKind::TimedOut,
+            "the function was canceled due to a timeout of thread-safe control",
+        )),
+        vex_sdk::FRESULT::FR_LOCKED => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "the operation to the object was rejected by file sharing control",
+        )),
+        vex_sdk::FRESULT::FR_NOT_ENOUGH_CORE => {
+            Err(io::const_error!(io::ErrorKind::OutOfMemory, "not enough memory for the operation"))
+        }
+        vex_sdk::FRESULT::FR_TOO_MANY_OPEN_FILES => Err(io::const_error!(
+            io::ErrorKind::Uncategorized,
+            "maximum number of open files has been reached",
+        )),
+        vex_sdk::FRESULT::FR_INVALID_PARAMETER => {
+            Err(io::const_error!(io::ErrorKind::InvalidInput, "a given parameter was invalid"))
+        }
+        _ => unreachable!(), // C-style enum
+    }
+}
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index f76a5f96c87..bd6fd5a3de4 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -26,15 +26,22 @@ impl Timespec {
     }
 
     fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
+            debug_assert!(a >= b);
+            a.wrapping_sub(b).cast_unsigned()
+        }
+
         if self >= other {
+            // Logic here is identical to Unix version of `Timestamp::sub_timespec`,
+            // check comments there why operations do not overflow.
             Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                 Duration::new(
-                    (self.t.tv_sec - other.t.tv_sec) as u64,
+                    sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec),
                     (self.t.tv_nsec - other.t.tv_nsec) as u32,
                 )
             } else {
                 Duration::new(
-                    (self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+                    sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec),
                     (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32,
                 )
             })
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index 513121c6d30..dd5e83ee570 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -45,6 +45,10 @@ cfg_select! {
         mod trusty;
         pub use self::trusty::*;
     }
+    target_os = "vexos" => {
+        mod vexos;
+        pub use self::vexos::*;
+    }
     all(target_os = "wasi", target_env = "p2") => {
         mod wasip2;
         pub use self::wasip2::*;
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index b50574de937..c0d69c3e002 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -92,6 +92,9 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ff
 ///
 /// Queries a handle to determine if it supports a specified protocol. If the protocol is
 /// supported by the handle, it opens the protocol on behalf of the calling agent.
+///
+/// The protocol is opened with the attribute GET_PROTOCOL, which means the caller is not required
+/// to close the protocol interface with `EFI_BOOT_SERVICES.CloseProtocol()`
 pub(crate) fn open_protocol<T>(
     handle: NonNull<crate::ffi::c_void>,
     mut protocol_guid: Guid,
@@ -473,6 +476,7 @@ impl<'a> crate::fmt::Debug for DevicePathNode<'a> {
     }
 }
 
+/// Protocols installed by Rust side on a handle.
 pub(crate) struct OwnedProtocol<T> {
     guid: r_efi::efi::Guid,
     handle: NonNull<crate::ffi::c_void>,
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 0d2100d66bc..51463eef5b7 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -72,7 +72,7 @@ mod imp {
     use crate::sync::OnceLock;
     use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering};
     use crate::sys::pal::unix::os;
-    use crate::{io, mem, panic, ptr};
+    use crate::{io, mem, ptr};
 
     // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
     // (unmapped pages) at the end of every thread's stack, so if a thread ends
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index bd7f74fea6a..c207f41cad4 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -134,28 +134,25 @@ impl Timespec {
     }
 
     pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        // When a >= b, the difference fits in u64.
+        fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
+            debug_assert!(a >= b);
+            a.wrapping_sub(b).cast_unsigned()
+        }
+
         if self >= other {
-            // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
-            // to optimize it into a branchless form (see also #75545):
-            //
-            // 1. `self.tv_sec - other.tv_sec` shows up as a common expression
-            //    in both branches, i.e. the `else` must have its `- 1`
-            //    subtraction after the common one, not interleaved with it
-            //    (it used to be `self.tv_sec - 1 - other.tv_sec`)
-            //
-            // 2. the `Duration::new` call (or any other additional complexity)
-            //    is outside of the `if`-`else`, not duplicated in both branches
-            //
-            // Ideally this code could be rearranged such that it more
-            // directly expresses the lower-cost behavior we want from it.
             let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() {
                 (
-                    (self.tv_sec - other.tv_sec) as u64,
+                    sub_ge_to_unsigned(self.tv_sec, other.tv_sec),
                     self.tv_nsec.as_inner() - other.tv_nsec.as_inner(),
                 )
             } else {
+                // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow.
+                debug_assert!(self.tv_nsec < other.tv_nsec);
+                debug_assert!(self.tv_sec > other.tv_sec);
+                debug_assert!(self.tv_sec > i64::MIN);
                 (
-                    (self.tv_sec - other.tv_sec - 1) as u64,
+                    sub_ge_to_unsigned(self.tv_sec - 1, other.tv_sec),
                     self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(),
                 )
             };
diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs
new file mode 100644
index 00000000000..61a34b0f68a
--- /dev/null
+++ b/library/std/src/sys/pal/vexos/mod.rs
@@ -0,0 +1,80 @@
+#[path = "../unsupported/os.rs"]
+pub mod os;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+pub mod time;
+
+#[expect(dead_code)]
+#[path = "../unsupported/common.rs"]
+mod unsupported_common;
+
+pub use unsupported_common::{
+    decode_error_kind, init, is_interrupted, unsupported, unsupported_err,
+};
+
+use crate::arch::global_asm;
+use crate::ptr;
+use crate::sys::stdio;
+use crate::time::{Duration, Instant};
+
+global_asm!(
+    r#"
+    .section .boot, "ax"
+    .global _boot
+
+    _boot:
+        ldr sp, =__stack_top @ Set up the user stack.
+        b _start             @ Jump to the Rust entrypoint.
+    "#
+);
+
+#[cfg(not(test))]
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn _start() -> ! {
+    unsafe extern "C" {
+        static mut __bss_start: u8;
+        static mut __bss_end: u8;
+
+        fn main() -> i32;
+    }
+
+    // Clear the .bss (uninitialized statics) section by filling it with zeroes.
+    // This is required, since the compiler assumes it will be zeroed on first access.
+    ptr::write_bytes(
+        &raw mut __bss_start,
+        0,
+        (&raw mut __bss_end).offset_from_unsigned(&raw mut __bss_start),
+    );
+
+    main();
+
+    cleanup();
+    abort_internal()
+}
+
+// SAFETY: must be called only once during runtime cleanup.
+// NOTE: this is not guaranteed to run, for example when the program aborts.
+pub unsafe fn cleanup() {
+    let exit_time = Instant::now();
+    const FLUSH_TIMEOUT: Duration = Duration::from_millis(15);
+
+    // Force the serial buffer to flush
+    while exit_time.elapsed() < FLUSH_TIMEOUT {
+        vex_sdk::vexTasksRun();
+
+        // If the buffer has been fully flushed, exit the loop
+        if vex_sdk::vexSerialWriteFree(stdio::STDIO_CHANNEL) == (stdio::STDOUT_BUF_SIZE as i32) {
+            break;
+        }
+    }
+}
+
+pub fn abort_internal() -> ! {
+    unsafe {
+        vex_sdk::vexSystemExitRequest();
+
+        loop {
+            vex_sdk::vexTasksRun();
+        }
+    }
+}
diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/pal/vexos/time.rs
new file mode 100644
index 00000000000..f95d96cd27a
--- /dev/null
+++ b/library/std/src/sys/pal/vexos/time.rs
@@ -0,0 +1,28 @@
+use crate::time::Duration;
+
+#[expect(dead_code)]
+#[path = "../unsupported/time.rs"]
+mod unsupported_time;
+pub use unsupported_time::{SystemTime, UNIX_EPOCH};
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+impl Instant {
+    pub fn now() -> Instant {
+        let micros = unsafe { vex_sdk::vexSystemHighResTimeGet() };
+        Self(Duration::from_micros(micros))
+    }
+
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.0.checked_sub(other.0)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_add(*other)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_sub(*other)?))
+    }
+}
diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs
index 9ef5496e57a..a1ed0cd2cdd 100644
--- a/library/std/src/sys/process/mod.rs
+++ b/library/std/src/sys/process/mod.rs
@@ -24,7 +24,7 @@ mod env;
 
 pub use env::CommandEnvs;
 pub use imp::{
-    Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes,
+    Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio,
 };
 
 #[cfg(any(
diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs
index 4864c586988..11c8b682bb9 100644
--- a/library/std/src/sys/process/uefi.rs
+++ b/library/std/src/sys/process/uefi.rs
@@ -6,6 +6,7 @@ pub use crate::ffi::OsString as EnvKey;
 use crate::ffi::{OsStr, OsString};
 use crate::num::{NonZero, NonZeroI32};
 use crate::path::Path;
+use crate::process::StdioPipes;
 use crate::sys::fs::File;
 use crate::sys::pal::helpers;
 use crate::sys::pal::os::error_string;
@@ -27,14 +28,6 @@ pub struct Command {
     env: CommandEnv,
 }
 
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 #[derive(Copy, Clone, Debug)]
 pub enum Stdio {
     Inherit,
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index ea45b08e90a..1d5909e99ba 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -9,6 +9,7 @@ use crate::collections::BTreeMap;
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::os::unix::prelude::*;
 use crate::path::Path;
+use crate::process::StdioPipes;
 use crate::sys::fd::FileDesc;
 use crate::sys::fs::File;
 #[cfg(not(target_os = "fuchsia"))]
@@ -104,14 +105,6 @@ pub struct Command {
     setsid: bool,
 }
 
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 // passed to do_exec() with configuration of what the child stdio should look
 // like
 #[cfg_attr(target_os = "vita", allow(dead_code))]
diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs
index d71be510b6a..3fae5ec1468 100644
--- a/library/std/src/sys/process/unix/fuchsia.rs
+++ b/library/std/src/sys/process/unix/fuchsia.rs
@@ -2,6 +2,7 @@ use libc::{c_int, size_t};
 
 use super::common::*;
 use crate::num::NonZero;
+use crate::process::StdioPipes;
 use crate::sys::pal::fuchsia::*;
 use crate::{fmt, io, mem, ptr};
 
diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs
index b4cf060fba9..cda1bf74f1c 100644
--- a/library/std/src/sys/process/unix/mod.rs
+++ b/library/std/src/sys/process/unix/mod.rs
@@ -23,5 +23,5 @@ cfg_select! {
 
 pub use imp::{ExitStatus, ExitStatusError, Process};
 
-pub use self::common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
+pub use self::common::{Command, CommandArgs, ExitCode, Stdio};
 pub use crate::ffi::OsString as EnvKey;
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 11d48878727..7d944f2f7ee 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -13,6 +13,7 @@ use libc::{gid_t, uid_t};
 use super::common::*;
 use crate::io::{self, Error, ErrorKind};
 use crate::num::NonZero;
+use crate::process::StdioPipes;
 use crate::sys::cvt;
 #[cfg(target_os = "linux")]
 use crate::sys::pal::linux::pidfd::PidFd;
diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs
index 87403cd50f8..9bda394f246 100644
--- a/library/std/src/sys/process/unix/unsupported.rs
+++ b/library/std/src/sys/process/unix/unsupported.rs
@@ -3,6 +3,7 @@ use libc::{c_int, pid_t};
 use super::common::*;
 use crate::io;
 use crate::num::NonZero;
+use crate::process::StdioPipes;
 use crate::sys::pal::unsupported::*;
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs
index b9298f5fa44..346ca6d74c9 100644
--- a/library/std/src/sys/process/unix/vxworks.rs
+++ b/library/std/src/sys/process/unix/vxworks.rs
@@ -4,6 +4,7 @@ use libc::{self, RTP_ID, c_char, c_int};
 use super::common::*;
 use crate::io::{self, ErrorKind};
 use crate::num::NonZero;
+use crate::process::StdioPipes;
 use crate::sys::{cvt, thread};
 use crate::{fmt, sys};
 
diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs
index 469922c78ac..636465b68e5 100644
--- a/library/std/src/sys/process/unsupported.rs
+++ b/library/std/src/sys/process/unsupported.rs
@@ -3,6 +3,7 @@ pub use crate::ffi::OsString as EnvKey;
 use crate::ffi::{OsStr, OsString};
 use crate::num::NonZero;
 use crate::path::Path;
+use crate::process::StdioPipes;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::unsupported;
@@ -23,14 +24,6 @@ pub struct Command {
     stderr: Option<Stdio>,
 }
 
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 #[derive(Debug)]
 pub enum Stdio {
     Inherit,
diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs
index f9e15b82475..1f2001bdc20 100644
--- a/library/std/src/sys/process/windows.rs
+++ b/library/std/src/sys/process/windows.rs
@@ -15,6 +15,7 @@ use crate::os::windows::ffi::{OsStrExt, OsStringExt};
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
 use crate::os::windows::process::ProcThreadAttributeList;
 use crate::path::{Path, PathBuf};
+use crate::process::StdioPipes;
 use crate::sync::Mutex;
 use crate::sys::args::{self, Arg};
 use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS};
@@ -169,12 +170,6 @@ pub enum Stdio {
     Handle(Handle),
 }
 
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
 impl Command {
     pub fn new(program: &OsStr) -> Command {
         Command {
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
index 1e0eec07b50..3c5a4c82a9f 100644
--- a/library/std/src/sys/random/mod.rs
+++ b/library/std/src/sys/random/mod.rs
@@ -101,6 +101,7 @@ cfg_select! {
     any(
         all(target_family = "wasm", target_os = "unknown"),
         target_os = "xous",
+        target_os = "vexos",
     ) => {
         // FIXME: finally remove std support for wasm32-unknown-unknown
         // FIXME: add random data generation to xous
@@ -116,6 +117,7 @@ cfg_select! {
     all(target_family = "wasm", target_os = "unknown"),
     all(target_os = "wasi", target_env = "p2"),
     target_os = "xous",
+    target_os = "vexos",
 )))]
 pub fn hashmap_random_keys() -> (u64, u64) {
     let mut buf = [0; 16];
diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs
index 7436e4d9de4..404ac877926 100644
--- a/library/std/src/sys/stdio/mod.rs
+++ b/library/std/src/sys/stdio/mod.rs
@@ -29,6 +29,10 @@ cfg_select! {
         mod uefi;
         pub use uefi::*;
     }
+    target_os = "vexos" => {
+        mod vexos;
+        pub use vexos::*;
+    }
     all(target_os = "wasi", target_env = "p1") => {
         mod wasip1;
         pub use wasip1::*;
diff --git a/library/std/src/sys/stdio/vexos.rs b/library/std/src/sys/stdio/vexos.rs
new file mode 100644
index 00000000000..9a391feb7a8
--- /dev/null
+++ b/library/std/src/sys/stdio/vexos.rs
@@ -0,0 +1,100 @@
+use crate::io;
+
+pub struct Stdin;
+pub struct Stdout;
+pub type Stderr = Stdout;
+
+pub const STDIO_CHANNEL: u32 = 1;
+
+impl Stdin {
+    pub const fn new() -> Stdin {
+        Stdin
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut count = 0;
+
+        for out_byte in buf.iter_mut() {
+            let byte = unsafe { vex_sdk::vexSerialReadChar(STDIO_CHANNEL) };
+            if byte < 0 {
+                break;
+            }
+
+            *out_byte = byte as u8;
+            count += 1;
+        }
+
+        Ok(count)
+    }
+}
+
+impl Stdout {
+    pub const fn new() -> Stdout {
+        Stdout
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let mut written = 0;
+
+        // HACK: VEXos holds an internal ringbuffer for serial writes that is flushed to USB1
+        // roughly every millisecond by `vexTasksRun`. For writes larger than 2048 bytes, we
+        // must block until that buffer is flushed to USB1 before writing the rest of `buf`.
+        //
+        // This is fairly nonstandard for a `write` implementation, but it avoids a guaranteed
+        // recursive panic when using macros such as `print!` to write large amounts of data
+        // (buf.len() > 2048) to stdout at once.
+        for chunk in buf.chunks(STDOUT_BUF_SIZE) {
+            if unsafe { vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize } < chunk.len() {
+                self.flush().unwrap();
+            }
+
+            let count: usize = unsafe {
+                vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, chunk.as_ptr(), chunk.len() as u32)
+            }
+            .try_into()
+            .map_err(|_| {
+                io::const_error!(io::ErrorKind::Uncategorized, "internal write error occurred")
+            })?;
+
+            written += count;
+
+            // This is a sanity check to ensure that we don't end up with non-contiguous
+            // buffer writes. e.g. a chunk gets only partially written, but we continue
+            // attempting to write the remaining chunks.
+            //
+            // In practice, this should never really occur since the previous flush ensures
+            // enough space in FIFO to write the entire chunk to vexSerialWriteBuffer.
+            if count != chunk.len() {
+                break;
+            }
+        }
+
+        Ok(written)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // This may block for up to a millisecond.
+        unsafe {
+            while (vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize) != STDOUT_BUF_SIZE {
+                vex_sdk::vexTasksRun();
+            }
+        }
+
+        Ok(())
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = 4096;
+pub const STDOUT_BUF_SIZE: usize = 2048;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    false
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Some(Stdout::new())
+}
diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs
index 6bb7fc1a20e..3bd83dd760a 100644
--- a/library/std/src/sys/thread/mod.rs
+++ b/library/std/src/sys/thread/mod.rs
@@ -81,6 +81,13 @@ cfg_select! {
         ))]
         pub use unsupported::set_name;
     }
+    target_os = "vexos" => {
+        mod vexos;
+        pub use vexos::{sleep, yield_now};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE};
+    }
     all(target_os = "wasi", target_env = "p1") => {
         mod wasip1;
         pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now};
diff --git a/library/std/src/sys/thread/vexos.rs b/library/std/src/sys/thread/vexos.rs
new file mode 100644
index 00000000000..d917dde4d0b
--- /dev/null
+++ b/library/std/src/sys/thread/vexos.rs
@@ -0,0 +1,17 @@
+use crate::time::{Duration, Instant};
+
+pub fn yield_now() {
+    unsafe {
+        vex_sdk::vexTasksRun();
+    }
+}
+
+pub fn sleep(dur: Duration) {
+    let start = Instant::now();
+
+    while start.elapsed() < dur {
+        unsafe {
+            vex_sdk::vexTasksRun();
+        }
+    }
+}
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
index cff74857c47..d5c795093cf 100644
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -29,6 +29,7 @@ cfg_select! {
         target_os = "uefi",
         target_os = "zkvm",
         target_os = "trusty",
+        target_os = "vexos",
     ) => {
         mod no_threads;
         pub use no_threads::{EagerStorage, LazyStorage, thread_local_inner};
@@ -98,6 +99,7 @@ pub(crate) mod guard {
             target_os = "uefi",
             target_os = "zkvm",
             target_os = "trusty",
+            target_os = "vexos",
         ) => {
             pub(crate) fn enable() {
                 // FIXME: Right now there is no concept of "thread exit" on
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 797feeb2bbb..0a6f2e5d508 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -230,7 +230,7 @@ impl fmt::Display for AccessError {
 impl Error for AccessError {}
 
 // This ensures the panicking code is outlined from `with` for `LocalKey`.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(panic = "immediate-abort"), inline(never))]
 #[track_caller]
 #[cold]
 fn panic_access_error(err: AccessError) -> ! {
diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs
index fa76c50597b..837a14b808f 100644
--- a/library/std/tests/path.rs
+++ b/library/std/tests/path.rs
@@ -2528,7 +2528,17 @@ fn normalize_lexically() {
 }
 
 #[test]
-/// See issue#146183
-fn compare_path_to_str() {
-    assert!(&PathBuf::from("x") == "x");
+/// See issue#146183 and issue#146940
+fn compare_path_like_to_str_like() {
+    let path_buf = PathBuf::from("x");
+    let path = Path::new("x");
+    let s = String::from("x");
+    assert!(path == "x");
+    assert!("x" == path);
+    assert!(path == &s);
+    assert!(&s == path);
+    assert!(&path_buf == "x");
+    assert!("x" == &path_buf);
+    assert!(path_buf == s);
+    assert!(s == path_buf);
 }
diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs
index 40709eae37c..be1948af915 100644
--- a/library/std/tests/time.rs
+++ b/library/std/tests/time.rs
@@ -227,3 +227,19 @@ fn big_math() {
     check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub);
     check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub);
 }
+
+#[test]
+#[cfg(unix)]
+fn system_time_duration_since_max_range_on_unix() {
+    // Repro regression https://github.com/rust-lang/rust/issues/146228
+
+    // Min and max values of `SystemTime` on Unix.
+    let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0));
+    let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999));
+
+    let delta_a = max.duration_since(min).expect("duration_since overflow");
+    let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration();
+
+    assert_eq!(Duration::MAX, delta_a);
+    assert_eq!(Duration::MAX, delta_b);
+}
diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs
index f5409361d93..8c9fd9647b8 100644
--- a/library/std_detect/src/detect/os/darwin/aarch64.rs
+++ b/library/std_detect/src/detect/os/darwin/aarch64.rs
@@ -37,24 +37,25 @@ pub(crate) fn detect_features() -> cache::Initializer {
     // Armv8.0 features not using the standard identifiers
     let fp = _sysctlbyname(c"hw.optional.floatingpoint");
     let asimd = _sysctlbyname(c"hw.optional.AdvSIMD");
-    let crc = _sysctlbyname(c"hw.optional.armv8_crc32");
+    let crc_old = _sysctlbyname(c"hw.optional.armv8_crc32");
 
     // Armv8 and Armv9 features using the standard identifiers
     let aes = _sysctlbyname(c"hw.optional.arm.FEAT_AES");
     let bf16 = _sysctlbyname(c"hw.optional.arm.FEAT_BF16");
     let bti = _sysctlbyname(c"hw.optional.arm.FEAT_BTI");
+    let crc = _sysctlbyname(c"hw.optional.arm.FEAT_CRC32");
     let cssc = _sysctlbyname(c"hw.optional.arm.FEAT_CSSC");
     let dit = _sysctlbyname(c"hw.optional.arm.FEAT_DIT");
+    let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd");
     let dpb = _sysctlbyname(c"hw.optional.arm.FEAT_DPB");
     let dpb2 = _sysctlbyname(c"hw.optional.arm.FEAT_DPB2");
-    let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd");
     let ecv = _sysctlbyname(c"hw.optional.arm.FEAT_ECV");
     let fcma = _sysctlbyname(c"hw.optional.arm.FEAT_FCMA");
     let fhm = _sysctlbyname(c"hw.optional.arm.FEAT_FHM");
-    let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16");
-    let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS");
     let flagm = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM");
     let flagm2 = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM2");
+    let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16");
+    let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS");
     let hbc = _sysctlbyname(c"hw.optional.arm.FEAT_HBC");
     let i8mm = _sysctlbyname(c"hw.optional.arm.FEAT_I8MM");
     let jsconv = _sysctlbyname(c"hw.optional.arm.FEAT_JSCVT");
@@ -62,6 +63,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
     let rcpc2 = _sysctlbyname(c"hw.optional.arm.FEAT_LRCPC2");
     let lse = _sysctlbyname(c"hw.optional.arm.FEAT_LSE");
     let lse2 = _sysctlbyname(c"hw.optional.arm.FEAT_LSE2");
+    let mte = _sysctlbyname(c"hw.optional.arm.FEAT_MTE");
+    let mte2 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE2");
     let pauth = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth");
     let pmull = _sysctlbyname(c"hw.optional.arm.FEAT_PMULL");
     let rdm = _sysctlbyname(c"hw.optional.arm.FEAT_RDM");
@@ -72,6 +75,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     let sha512 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA512");
     let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME");
     let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2");
+    let sme2p1 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2p1");
     let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64");
     let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64");
     let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS");
@@ -87,6 +91,12 @@ pub(crate) fn detect_features() -> cache::Initializer {
     let ebf16 = _sysctlbyname(c"hw.optional.arm.FEAT_EBF16");
     let fpac = _sysctlbyname(c"hw.optional.arm.FEAT_FPAC");
     let fpaccombine = _sysctlbyname(c"hw.optional.arm.FEAT_FPACCOMBINE");
+    let mte_async = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_ASYNC");
+    let mte_canonical_tags = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_CANONICAL_TAGS");
+    let mte_no_address_tags = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_NO_ADDRESS_TAGS");
+    let mte_store_only = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_STORE_ONLY");
+    let mte3 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE3");
+    let mte4 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE4");
     let pacimp = _sysctlbyname(c"hw.optional.arm.FEAT_PACIMP");
     let pauth2 = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth2");
     let rpres = _sysctlbyname(c"hw.optional.arm.FEAT_RPRES");
@@ -111,7 +121,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     enable_feature(Feature::asimd, asimd);
     enable_feature(Feature::bf16, bf16);
     enable_feature(Feature::bti, bti);
-    enable_feature(Feature::crc, crc);
+    enable_feature(Feature::crc, crc_old || crc);
     enable_feature(Feature::cssc, cssc);
     enable_feature(Feature::dit, dit);
     enable_feature(Feature::dotprod, dotprod);
@@ -130,6 +140,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     enable_feature(Feature::jsconv, jsconv);
     enable_feature(Feature::lse, lse);
     enable_feature(Feature::lse2, lse2);
+    enable_feature(Feature::mte, mte && mte2);
     enable_feature(Feature::paca, pauth);
     enable_feature(Feature::pacg, pauth);
     enable_feature(Feature::pmull, aes && pmull);
@@ -141,6 +152,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     enable_feature(Feature::sha3, sha512 && sha3 && asimd);
     enable_feature(Feature::sme, sme);
     enable_feature(Feature::sme2, sme2);
+    enable_feature(Feature::sme2p1, sme2p1);
     enable_feature(Feature::sme_f64f64, sme_f64f64);
     enable_feature(Feature::sme_i16i64, sme_i16i64);
     enable_feature(Feature::ssbs, ssbs);
diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs
index 855261aaecf..63af53a8e74 100644
--- a/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs
+++ b/library/stdarch/crates/core_arch/src/aarch64/neon/generated.rs
@@ -10306,7 +10306,7 @@ pub fn vfmad_lane_f64<const LANE: i32>(a: f64, b: f64, c: float64x1_t) -> f64 {
 #[unstable(feature = "stdarch_neon_f16", issue = "136306")]
 #[cfg(not(target_arch = "arm64ec"))]
 pub fn vfmah_f16(a: f16, b: f16, c: f16) -> f16 {
-    unsafe { fmaf16(b, c, a) }
+    fmaf16(b, c, a)
 }
 #[doc = "Floating-point fused multiply-add to accumulator"]
 #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vfmah_lane_f16)"]
@@ -22448,7 +22448,7 @@ pub fn vrndaq_f64(a: float64x2_t) -> float64x2_t {
 #[cfg(not(target_arch = "arm64ec"))]
 #[cfg_attr(test, assert_instr(frinta))]
 pub fn vrndah_f16(a: f16) -> f16 {
-    unsafe { roundf16(a) }
+    roundf16(a)
 }
 #[doc = "Floating-point round to integral, to nearest with ties to away"]
 #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndh_f16)"]
@@ -22458,7 +22458,7 @@ pub fn vrndah_f16(a: f16) -> f16 {
 #[cfg(not(target_arch = "arm64ec"))]
 #[cfg_attr(test, assert_instr(frintz))]
 pub fn vrndh_f16(a: f16) -> f16 {
-    unsafe { truncf16(a) }
+    truncf16(a)
 }
 #[doc = "Floating-point round to integral, using current rounding mode"]
 #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndi_f16)"]
@@ -22639,7 +22639,7 @@ pub fn vrndmq_f64(a: float64x2_t) -> float64x2_t {
 #[cfg(not(target_arch = "arm64ec"))]
 #[cfg_attr(test, assert_instr(frintm))]
 pub fn vrndmh_f16(a: f16) -> f16 {
-    unsafe { floorf16(a) }
+    floorf16(a)
 }
 #[doc = "Floating-point round to integral, to nearest with ties to even"]
 #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndn_f64)"]
@@ -22770,7 +22770,7 @@ pub fn vrndpq_f64(a: float64x2_t) -> float64x2_t {
 #[cfg(not(target_arch = "arm64ec"))]
 #[cfg_attr(test, assert_instr(frintp))]
 pub fn vrndph_f16(a: f16) -> f16 {
-    unsafe { ceilf16(a) }
+    ceilf16(a)
 }
 #[doc = "Floating-point round to integral exact, using current rounding mode"]
 #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vrndx_f16)"]
@@ -24268,7 +24268,7 @@ pub fn vsqrtq_f64(a: float64x2_t) -> float64x2_t {
 #[cfg(not(target_arch = "arm64ec"))]
 #[cfg_attr(test, assert_instr(fsqrt))]
 pub fn vsqrth_f16(a: f16) -> f16 {
-    unsafe { sqrtf16(a) }
+    sqrtf16(a)
 }
 #[doc = "Shift Right and Insert (immediate)"]
 #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vsri_n_s8)"]
diff --git a/library/stdarch/crates/core_arch/src/wasm32/mod.rs b/library/stdarch/crates/core_arch/src/wasm32/mod.rs
index 60049c73295..01bf0a71658 100644
--- a/library/stdarch/crates/core_arch/src/wasm32/mod.rs
+++ b/library/stdarch/crates/core_arch/src/wasm32/mod.rs
@@ -43,7 +43,7 @@ pub fn unreachable() -> ! {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f32_ceil(a: f32) -> f32 {
-    unsafe { crate::intrinsics::ceilf32(a) }
+    crate::intrinsics::ceilf32(a)
 }
 
 /// Generates the [`f32.floor`] instruction, returning the largest integer less than or equal to `a`.
@@ -57,7 +57,7 @@ pub fn f32_ceil(a: f32) -> f32 {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f32_floor(a: f32) -> f32 {
-    unsafe { crate::intrinsics::floorf32(a) }
+    crate::intrinsics::floorf32(a)
 }
 
 /// Generates the [`f32.trunc`] instruction, roundinging to the nearest integer towards zero.
@@ -71,7 +71,7 @@ pub fn f32_floor(a: f32) -> f32 {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f32_trunc(a: f32) -> f32 {
-    unsafe { crate::intrinsics::truncf32(a) }
+    crate::intrinsics::truncf32(a)
 }
 
 /// Generates the [`f32.nearest`] instruction, roundinging to the nearest integer. Rounds half-way
@@ -100,7 +100,7 @@ pub fn f32_nearest(a: f32) -> f32 {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f32_sqrt(a: f32) -> f32 {
-    unsafe { crate::intrinsics::sqrtf32(a) }
+    crate::intrinsics::sqrtf32(a)
 }
 
 /// Generates the [`f64.ceil`] instruction, returning the smallest integer greater than or equal to `a`.
@@ -114,7 +114,7 @@ pub fn f32_sqrt(a: f32) -> f32 {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f64_ceil(a: f64) -> f64 {
-    unsafe { crate::intrinsics::ceilf64(a) }
+    crate::intrinsics::ceilf64(a)
 }
 
 /// Generates the [`f64.floor`] instruction, returning the largest integer less than or equal to `a`.
@@ -128,7 +128,7 @@ pub fn f64_ceil(a: f64) -> f64 {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f64_floor(a: f64) -> f64 {
-    unsafe { crate::intrinsics::floorf64(a) }
+    crate::intrinsics::floorf64(a)
 }
 
 /// Generates the [`f64.trunc`] instruction, roundinging to the nearest integer towards zero.
@@ -142,7 +142,7 @@ pub fn f64_floor(a: f64) -> f64 {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f64_trunc(a: f64) -> f64 {
-    unsafe { crate::intrinsics::truncf64(a) }
+    crate::intrinsics::truncf64(a)
 }
 
 /// Generates the [`f64.nearest`] instruction, roundinging to the nearest integer. Rounds half-way
@@ -171,7 +171,7 @@ pub fn f64_nearest(a: f64) -> f64 {
 #[must_use = "method returns a new number and does not mutate the original value"]
 #[unstable(feature = "wasm_numeric_instr", issue = "133908")]
 pub fn f64_sqrt(a: f64) -> f64 {
-    unsafe { crate::intrinsics::sqrtf64(a) }
+    crate::intrinsics::sqrtf64(a)
 }
 
 unsafe extern "C-unwind" {
diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml
index ccdcea980e1..34b330e1b85 100644
--- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml
+++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/aarch64.spec.yml
@@ -3108,7 +3108,7 @@ intrinsics:
     types:
       - [f16, 'h_']
     compose:
-      - FnCall: [roundf16, [a], [], true]
+      - FnCall: [roundf16, [a], []]
 
   - name: "vrndn{neon_type.no}"
     doc: "Floating-point round to integral, to nearest with ties to even"
@@ -3208,7 +3208,7 @@ intrinsics:
     types:
       - [f16, 'h_']
     compose:
-      - FnCall: [floorf16, [a], [], true]
+      - FnCall: [floorf16, [a], []]
 
 
 
@@ -3257,7 +3257,7 @@ intrinsics:
     types:
       - [f16, 'h_']
     compose:
-      - FnCall: [ceilf16, [a], [], true]
+      - FnCall: [ceilf16, [a], []]
 
   - name: "vrnd{neon_type.no}"
     doc: "Floating-point round to integral, toward zero"
@@ -3304,7 +3304,7 @@ intrinsics:
     types:
       - [f16, 'h_']
     compose:
-      - FnCall: [truncf16, [a], [], true]
+      - FnCall: [truncf16, [a], []]
 
 
   - name: "vrndi{neon_type.no}"
@@ -8499,7 +8499,7 @@ intrinsics:
     types:
       - [f16, 'h_']
     compose:
-      - FnCall: [sqrtf16, [a], [], true]
+      - FnCall: [sqrtf16, [a], []]
 
   - name: "vrsqrts{type[0]}"
     doc: "Floating-point reciprocal square root step"
@@ -10464,7 +10464,7 @@ intrinsics:
     types:
       - ["f16", "h_f16"]
     compose:
-      - FnCall: [fmaf16, [b, c, a], [], true]
+      - FnCall: [fmaf16, [b, c, a], []]
 
 
   - name: "vfmah_lane{type[2]}"
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 7b4aeed94e9..ee4aec61872 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -31,7 +31,6 @@ llvm-libunwind = ["std/llvm-libunwind"]
 system-llvm-libunwind = ["std/system-llvm-libunwind"]
 optimize_for_size = ["std/optimize_for_size"]
 panic-unwind = ["std/panic-unwind"]
-panic_immediate_abort = ["std/panic_immediate_abort"]
 profiler = ["dep:profiler_builtins"]
 std_detect_file_io = ["std/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index effd33d288f..8b1775178c9 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -596,6 +596,7 @@ class RustBuild(object):
         self.download_url = (
             os.getenv("RUSTUP_DIST_SERVER") or self.stage0_data["dist_server"]
         )
+        self.jobs = self.get_toml("jobs", "build") or "default"
 
         self.build = args.build or self.build_triple()
 
@@ -1144,6 +1145,7 @@ class RustBuild(object):
         args = [
             self.cargo(),
             "build",
+            "--jobs=" + self.jobs,
             "--manifest-path",
             os.path.join(self.rust_root, "src/bootstrap/Cargo.toml"),
             "-Zroot-dir=" + self.rust_root,
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 2083c675e1f..d5b15d79086 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -564,6 +564,7 @@ impl Step for CI {
                 "clippy::same_item_push".into(),
                 "clippy::single_char_add_str".into(),
                 "clippy::to_string_in_format_args".into(),
+                "clippy::unconditional_recursion".into(),
             ],
             forbid: vec![],
         };
@@ -591,6 +592,7 @@ impl Step for CI {
                 "clippy::same_item_push".into(),
                 "clippy::single_char_add_str".into(),
                 "clippy::to_string_in_format_args".into(),
+                "clippy::unconditional_recursion".into(),
             ],
             forbid: vec![],
         };
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 14104d7d1d7..884b5750974 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -895,6 +895,8 @@ impl Step for StartupObjects {
     fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
         let for_compiler = self.compiler;
         let target = self.target;
+        // Even though no longer necessary on x86_64, they are kept for now to
+        // avoid potential issues in downstream crates.
         if !target.is_windows_gnu() {
             return vec![];
         }
@@ -1832,8 +1834,9 @@ impl Step for Sysroot {
         let sysroot = sysroot_dir(compiler.stage);
         trace!(stage = ?compiler.stage, ?sysroot);
 
-        builder
-            .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display()));
+        builder.do_if_verbose(|| {
+            println!("Removing sysroot {} to avoid caching bugs", sysroot.display())
+        });
         let _ = fs::remove_dir_all(&sysroot);
         t!(fs::create_dir_all(&sysroot));
 
@@ -1902,12 +1905,7 @@ impl Step for Sysroot {
                 if !path.parent().is_none_or(|p| p.ends_with(&suffix)) {
                     return true;
                 }
-                if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) {
-                    builder.verbose_than(1, || println!("ignoring {}", path.display()));
-                    false
-                } else {
-                    true
-                }
+                filtered_files.iter().all(|f| f != path.file_name().unwrap())
             });
         }
 
@@ -2596,7 +2594,7 @@ pub fn stream_cargo(
         cmd.arg(arg);
     }
 
-    builder.verbose(|| println!("running: {cmd:?}"));
+    builder.do_if_verbose(|| println!("running: {cmd:?}"));
 
     let streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx);
 
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 99a1062109a..b79d2cb413d 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2304,7 +2304,7 @@ fn maybe_install_llvm(
         let mut cmd = command(host_llvm_config);
         cmd.cached();
         cmd.arg("--libfiles");
-        builder.verbose(|| println!("running {cmd:?}"));
+        builder.do_if_verbose(|| println!("running {cmd:?}"));
         let files = cmd.run_capture_stdout(builder).stdout();
         let build_llvm_out = &builder.llvm_out(builder.config.host_target);
         let target_llvm_out = &builder.llvm_out(target);
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index 717dea37e9e..17ab8c4e2f4 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -128,7 +128,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
         &builder.config,
         builder.config.rust_info.is_managed_git_subrepository(),
     );
-    builder.verbose(|| {
+    builder.do_if_verbose(|| {
         eprintln!("GCC freshness: {source:?}");
     });
     match source {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index e7f5879b5f5..ca2731819e7 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -582,11 +582,11 @@ impl Miri {
         // We re-use the `cargo` from above.
         cargo.arg("--print-sysroot");
 
-        builder.verbose(|| println!("running: {cargo:?}"));
+        builder.do_if_verbose(|| println!("running: {cargo:?}"));
         let stdout = cargo.run_capture_stdout(builder).stdout();
         // Output is "<sysroot>\n".
         let sysroot = stdout.trim_end();
-        builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
+        builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
         PathBuf::from(sysroot)
     }
 }
@@ -2675,7 +2675,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
         return true;
     }
 
-    builder.verbose(|| println!("doc tests for: {}", markdown.display()));
+    builder.do_if_verbose(|| println!("doc tests for: {}", markdown.display()));
     let mut cmd = builder.rustdoc_cmd(compiler);
     builder.add_rust_test_threads(&mut cmd);
     // allow for unstable options such as new editions
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index ee2bb710674..9fc4ce669c2 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -1139,7 +1139,7 @@ impl Builder<'_> {
             cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
         }
 
-        if self.is_verbose_than(1) {
+        if self.verbosity >= 2 {
             // This provides very useful logs especially when debugging build cache-related stuff.
             cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info");
         }
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 8226b4325b6..049d2647bec 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -545,7 +545,7 @@ impl StepDescription {
         if !builder.config.skip.is_empty()
             && !matches!(builder.config.get_dry_run(), DryRun::SelfCheck)
         {
-            builder.verbose(|| {
+            builder.do_if_verbose(|| {
                 println!(
                     "{:?} not skipped for {:?} -- not in {:?}",
                     pathset, self.name, builder.config.skip
@@ -947,7 +947,7 @@ impl Step for Libdir {
             // Sysroot`).
             if !builder.download_rustc() {
                 let sysroot_target_libdir = sysroot.join(self.target).join("lib");
-                builder.verbose(|| {
+                builder.do_if_verbose(|| {
                     eprintln!(
                         "Removing sysroot {} to avoid caching bugs",
                         sysroot_target_libdir.display()
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 229adf71459..4555f0d2091 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -22,13 +22,7 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
 }
 
 fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config {
-    TestCtx::new()
-        .config(cmd[0])
-        .args(&cmd[1..])
-        .hosts(host)
-        .targets(target)
-        .args(&["--build", TEST_TRIPLE_1])
-        .create_config()
+    TestCtx::new().config(cmd[0]).args(&cmd[1..]).hosts(host).targets(target).create_config()
 }
 
 fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
@@ -218,18 +212,17 @@ fn prepare_rustc_checkout(ctx: &mut GitCtx) {
 
 /// Parses a Config directory from `path`, with the given value of `download_rustc`.
 fn parse_config_download_rustc_at(path: &Path, download_rustc: &str, ci: bool) -> Config {
-    Config::parse_inner(
-        Flags::parse(&[
-            "build".to_owned(),
-            "--dry-run".to_owned(),
-            "--ci".to_owned(),
-            if ci { "true" } else { "false" }.to_owned(),
-            format!("--set=rust.download-rustc='{download_rustc}'"),
-            "--src".to_owned(),
-            path.to_str().unwrap().to_owned(),
-        ]),
-        |&_| Ok(Default::default()),
-    )
+    TestCtx::new()
+        .config("build")
+        .args(&[
+            "--ci",
+            if ci { "true" } else { "false" },
+            format!("--set=rust.download-rustc='{download_rustc}'").as_str(),
+            "--src",
+            path.to_str().unwrap(),
+        ])
+        .no_override_download_ci_llvm()
+        .create_config()
 }
 
 mod dist {
@@ -237,6 +230,7 @@ mod dist {
 
     use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, first, run_build};
     use crate::Flags;
+    use crate::core::builder::tests::host_target;
     use crate::core::builder::*;
 
     fn configure(host: &[&str], target: &[&str]) -> Config {
@@ -245,11 +239,11 @@ mod dist {
 
     #[test]
     fn llvm_out_behaviour() {
-        let mut config = configure(&[TEST_TRIPLE_1], &[TEST_TRIPLE_2]);
+        let mut config = configure(&[], &[TEST_TRIPLE_2]);
         config.llvm_from_ci = true;
         let build = Build::new(config.clone());
 
-        let target = TargetSelection::from_user(TEST_TRIPLE_1);
+        let target = TargetSelection::from_user(&host_target());
         assert!(build.llvm_out(target).ends_with("ci-llvm"));
         let target = TargetSelection::from_user(TEST_TRIPLE_2);
         assert!(build.llvm_out(target).ends_with("llvm"));
@@ -314,7 +308,7 @@ mod sysroot_target_dirs {
 /// cg_gcc tests instead.
 #[test]
 fn test_test_compiler() {
-    let config = configure_with_args(&["test", "compiler"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+    let config = configure_with_args(&["test", "compiler"], &[&host_target()], &[TEST_TRIPLE_1]);
     let cache = run_build(&config.paths.clone(), config);
 
     let compiler = cache.contains::<test::CrateLibrustc>();
@@ -347,7 +341,7 @@ fn test_test_coverage() {
         // Print each test case so that if one fails, the most recently printed
         // case is the one that failed.
         println!("Testing case: {cmd:?}");
-        let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+        let config = configure_with_args(cmd, &[], &[TEST_TRIPLE_1]);
         let mut cache = run_build(&config.paths.clone(), config);
 
         let modes =
@@ -359,14 +353,7 @@ fn test_test_coverage() {
 #[test]
 fn test_prebuilt_llvm_config_path_resolution() {
     fn configure(config: &str) -> Config {
-        Config::parse_inner(
-            Flags::parse(&[
-                "build".to_string(),
-                "--dry-run".to_string(),
-                "--config=/does/not/exist".to_string(),
-            ]),
-            |&_| toml::from_str(&config),
-        )
+        TestCtx::new().config("build").with_default_toml_config(config).create_config()
     }
 
     // Removes Windows disk prefix if present
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index dd2d5a1fd53..6d9e3b54156 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -414,14 +414,28 @@ impl Config {
         // Set config values based on flags.
         let mut exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast());
         exec_ctx.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled });
-        let mut src = {
+
+        let default_src_dir = {
             let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
             // Undo `src/bootstrap`
             manifest_dir.parent().unwrap().parent().unwrap().to_owned()
         };
+        let src = if let Some(s) = compute_src_directory(flags_src, &exec_ctx) {
+            s
+        } else {
+            default_src_dir.clone()
+        };
 
-        if let Some(src_) = compute_src_directory(flags_src, &exec_ctx) {
-            src = src_;
+        #[cfg(test)]
+        {
+            if let Some(config_path) = flags_config.as_ref() {
+                assert!(
+                    !config_path.starts_with(&src),
+                    "Path {config_path:?} should not be inside or equal to src dir {src:?}"
+                );
+            } else {
+                panic!("During test the config should be explicitly added");
+            }
         }
 
         // Now load the TOML config, as soon as possible
@@ -630,19 +644,13 @@ impl Config {
         let llvm_assertions = llvm_assertions.unwrap_or(false);
         let mut target_config = HashMap::new();
         let mut channel = "dev".to_string();
-        let out = flags_build_dir.or(build_build_dir.map(PathBuf::from)).unwrap_or_else(|| {
-            if cfg!(test) {
-                // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
-                Path::new(
-                    &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"),
-                )
-                .parent()
-                .unwrap()
-                .to_path_buf()
-            } else {
-                PathBuf::from("build")
-            }
-        });
+
+        let out = flags_build_dir.or_else(|| build_build_dir.map(PathBuf::from));
+        let out = if cfg!(test) {
+            out.expect("--build-dir has to be specified in tests")
+        } else {
+            out.unwrap_or_else(|| PathBuf::from("build"))
+        };
 
         // NOTE: Bootstrap spawns various commands with different working directories.
         // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
@@ -653,6 +661,10 @@ impl Config {
             out
         };
 
+        let default_stage0_rustc_path = |dir: &Path| {
+            dir.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target))
+        };
+
         if cfg!(test) {
             // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the
             // same ones used to call the tests (if custom ones are not defined in the toml). If we
@@ -661,6 +673,22 @@ impl Config {
             // Cargo in their bootstrap.toml.
             build_rustc = build_rustc.take().or(std::env::var_os("RUSTC").map(|p| p.into()));
             build_cargo = build_cargo.take().or(std::env::var_os("CARGO").map(|p| p.into()));
+
+            // If we are running only `cargo test` (and not `x test bootstrap`), which is useful
+            // e.g. for debugging bootstrap itself, then we won't have RUSTC and CARGO set to the
+            // proper paths.
+            // We thus "guess" that the build directory is located at <src>/build, and try to load
+            // rustc and cargo from there
+            let is_test_outside_x = std::env::var("CARGO_TARGET_DIR").is_err();
+            if is_test_outside_x && build_rustc.is_none() {
+                let stage0_rustc = default_stage0_rustc_path(&default_src_dir.join("build"));
+                assert!(
+                    stage0_rustc.exists(),
+                    "Trying to run cargo test without having a stage0 rustc available in {}",
+                    stage0_rustc.display()
+                );
+                build_rustc = Some(stage0_rustc);
+            }
         }
 
         if !flags_skip_stage0_validation {
@@ -694,7 +722,7 @@ impl Config {
 
         let initial_rustc = build_rustc.unwrap_or_else(|| {
             download_beta_toolchain(&dwn_ctx, &out);
-            out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target))
+            default_stage0_rustc_path(&out)
         });
 
         let initial_sysroot = t!(PathBuf::from_str(
@@ -1534,11 +1562,11 @@ impl Config {
                                 println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
                                 println!("HELP: Consider rebasing to a newer commit if available.");
                                 return None;
-                            },
+                            }
                             Err(e) => {
                                 eprintln!("ERROR: Failed to parse CI rustc bootstrap.toml: {e}");
                                 exit!(2);
-                            },
+                            }
                         };
 
                         let current_config_toml = Self::get_toml(config_path).unwrap();
@@ -1571,8 +1599,8 @@ impl Config {
     }
 
     /// Runs a function if verbosity is greater than 0
-    pub fn verbose(&self, f: impl Fn()) {
-        self.exec_ctx.verbose(f);
+    pub fn do_if_verbose(&self, f: impl Fn()) {
+        self.exec_ctx.do_if_verbose(f);
     }
 
     pub fn any_sanitizers_to_build(&self) -> bool {
@@ -2061,7 +2089,7 @@ pub fn download_ci_rustc_commit<'a>(
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
-        dwn_ctx.exec_ctx.verbose(|| {
+        dwn_ctx.exec_ctx.do_if_verbose(|| {
             eprintln!("rustc freshness: {freshness:?}");
         });
         match freshness {
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index e93525fbd09..4f2df76a156 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -14,17 +14,15 @@ use super::toml::change_id::ChangeIdWrapper;
 use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS};
 use crate::ChangeId;
 use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};
-use crate::core::build_steps::llvm;
 use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
+use crate::core::build_steps::{llvm, test};
 use crate::core::config::toml::TomlConfig;
 use crate::core::config::{CompilerBuiltins, LldMode, StringOrBool, Target, TargetSelection};
+use crate::utils::tests::TestCtx;
 use crate::utils::tests::git::git_test;
 
 pub(crate) fn parse(config: &str) -> Config {
-    Config::parse_inner(
-        Flags::parse(&["check".to_string(), "--config=/does/not/exist".to_string()]),
-        |&_| toml::from_str(&config),
-    )
+    TestCtx::new().config("check").with_default_toml_config(config).create_config()
 }
 
 fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
@@ -32,28 +30,16 @@ fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
     toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table))
 }
 
-/// Helps with debugging by using consistent test-specific directories instead of
-/// random temporary directories.
-fn prepare_test_specific_dir() -> PathBuf {
-    let current = std::thread::current();
-    // Replace "::" with "_" to make it safe for directory names on Windows systems
-    let test_path = current.name().unwrap().replace("::", "_");
-
-    let testdir = parse("").tempdir().join(test_path);
-
-    // clean up any old test files
-    let _ = fs::remove_dir_all(&testdir);
-    let _ = fs::create_dir_all(&testdir);
-
-    testdir
-}
-
 #[test]
 fn download_ci_llvm() {
-    let config = parse("llvm.download-ci-llvm = false");
+    let config = TestCtx::new().config("check").create_config();
     assert!(!config.llvm_from_ci);
 
-    let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\"");
+    // this doesn't make sense, as we are overriding it later.
+    let if_unchanged_config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config("llvm.download-ci-llvm = \"if-unchanged\"")
+        .create_config();
     if if_unchanged_config.llvm_from_ci && if_unchanged_config.is_running_on_ci {
         let has_changes = if_unchanged_config.has_changes_from_upstream(LLVM_INVALIDATION_PATHS);
 
@@ -64,62 +50,6 @@ fn download_ci_llvm() {
     }
 }
 
-// FIXME(onur-ozkan): extend scope of the test
-// refs:
-//   - https://github.com/rust-lang/rust/issues/109120
-//   - https://github.com/rust-lang/rust/pull/109162#issuecomment-1496782487
-#[test]
-fn detect_src_and_out() {
-    fn test(cfg: Config, build_dir: Option<&str>) {
-        // This will bring absolute form of `src/bootstrap` path
-        let current_dir = std::env::current_dir().unwrap();
-
-        // get `src` by moving into project root path
-        let expected_src = current_dir.ancestors().nth(2).unwrap();
-        assert_eq!(&cfg.src, expected_src);
-
-        // Sanity check for `src`
-        let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
-        let expected_src = manifest_dir.ancestors().nth(2).unwrap();
-        assert_eq!(&cfg.src, expected_src);
-
-        // test if build-dir was manually given in bootstrap.toml
-        if let Some(custom_build_dir) = build_dir {
-            assert_eq!(&cfg.out, Path::new(custom_build_dir));
-        }
-        // test the native bootstrap way
-        else {
-            // This should bring output path of bootstrap in absolute form
-            let cargo_target_dir = env::var_os("CARGO_TARGET_DIR").expect(
-                "CARGO_TARGET_DIR must been provided for the test environment from bootstrap",
-            );
-
-            // Move to `build` from `build/bootstrap`
-            let expected_out = Path::new(&cargo_target_dir).parent().unwrap();
-            assert_eq!(&cfg.out, expected_out);
-
-            let args: Vec<String> = env::args().collect();
-
-            // Another test for `out` as a sanity check
-            //
-            // This will bring something similar to:
-            //     `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804`
-            // `{build-dir}` can be anywhere, not just in the rust project directory.
-            let dep = Path::new(args.first().unwrap());
-            let expected_out = dep.ancestors().nth(5).unwrap();
-
-            assert_eq!(&cfg.out, expected_out);
-        }
-    }
-
-    test(parse(""), None);
-
-    {
-        let build_dir = if cfg!(windows) { "C:\\tmp" } else { "/tmp" };
-        test(parse(&format!("build.build-dir = '{build_dir}'")), Some(build_dir));
-    }
-}
-
 #[test]
 fn clap_verify() {
     Flags::command().debug_assert();
@@ -127,54 +57,54 @@ fn clap_verify() {
 
 #[test]
 fn override_toml() {
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--set=change-id=1".to_owned(),
-            "--set=rust.lto=fat".to_owned(),
-            "--set=rust.deny-warnings=false".to_owned(),
-            "--set=build.optimized-compiler-builtins=true".to_owned(),
-            "--set=build.gdb=\"bar\"".to_owned(),
-            "--set=build.tools=[\"cargo\"]".to_owned(),
-            "--set=llvm.build-config={\"foo\" = \"bar\"}".to_owned(),
-            "--set=target.x86_64-unknown-linux-gnu.runner=bar".to_owned(),
-            "--set=target.x86_64-unknown-linux-gnu.rpath=false".to_owned(),
-            "--set=target.aarch64-unknown-linux-gnu.sanitizers=false".to_owned(),
-            "--set=target.aarch64-apple-darwin.runner=apple".to_owned(),
-            "--set=target.aarch64-apple-darwin.optimized-compiler-builtins=false".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
-change-id = 0
-[rust]
-lto = "off"
-deny-warnings = true
-download-rustc=false
-
-[build]
-gdb = "foo"
-tools = []
-
-[llvm]
-download-ci-llvm = false
-build-config = {}
-
-[target.aarch64-unknown-linux-gnu]
-sanitizers = true
-rpath = true
-runner = "aarch64-runner"
-
-[target.x86_64-unknown-linux-gnu]
-sanitizers = true
-rpath = true
-runner = "x86_64-runner"
-
-                "#,
-            )
-        },
-    );
+    let config_toml: &str = r#"
+    change-id = 0
+
+    [rust]
+    lto = "off"
+    deny-warnings = true
+    download-rustc = false
+
+    [build]
+    gdb = "foo"
+    tools = []
+
+    [llvm]
+    download-ci-llvm = false
+    build-config = {}
+
+    [target.aarch64-unknown-linux-gnu]
+    sanitizers = true
+    rpath = true
+    runner = "aarch64-runner"
+
+    [target.x86_64-unknown-linux-gnu]
+    sanitizers = true
+    rpath = true
+    runner = "x86_64-runner"
+    "#;
+
+    let args = [
+        "--set=change-id=1",
+        "--set=rust.lto=fat",
+        "--set=rust.deny-warnings=false",
+        "--set=build.optimized-compiler-builtins=true",
+        "--set=build.gdb=\"bar\"",
+        "--set=build.tools=[\"cargo\"]",
+        "--set=llvm.build-config={\"foo\" = \"bar\"}",
+        "--set=target.x86_64-unknown-linux-gnu.runner=bar",
+        "--set=target.x86_64-unknown-linux-gnu.rpath=false",
+        "--set=target.aarch64-unknown-linux-gnu.sanitizers=false",
+        "--set=target.aarch64-apple-darwin.runner=apple",
+        "--set=target.aarch64-apple-darwin.optimized-compiler-builtins=false",
+    ];
+
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config(config_toml)
+        .args(&args)
+        .create_config();
+
     assert_eq!(config.change_id, Some(ChangeId::Id(1)), "setting top-level value");
     assert_eq!(
         config.rust_lto,
@@ -233,33 +163,26 @@ runner = "x86_64-runner"
 #[test]
 #[should_panic]
 fn override_toml_duplicate() {
-    Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_string(),
-            "--set=change-id=1".to_owned(),
-            "--set=change-id=2".to_owned(),
-        ]),
-        |&_| toml::from_str("change-id = 0"),
-    );
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config("change-id = 0")
+        .arg("--set")
+        .arg("change-id=1")
+        .arg("--set")
+        .arg("change-id=2")
+        .create_config();
 }
 
 #[test]
 fn profile_user_dist() {
-    fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
-        let contents = if file.ends_with("bootstrap.toml")
-            || file.ends_with("config.toml")
-            || env::var_os("RUST_BOOTSTRAP_CONFIG").is_some()
-        {
-            "profile = \"user\"".to_owned()
-        } else {
-            assert!(file.ends_with("config.dist.toml") || file.ends_with("bootstrap.dist.toml"));
-            std::fs::read_to_string(file).unwrap()
-        };
-
-        toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table))
-    }
-    Config::parse_inner(Flags::parse(&["check".to_owned()]), get_toml);
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        profile = "user"
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
@@ -277,12 +200,15 @@ fn rust_optimize() {
 #[test]
 #[should_panic]
 fn invalid_rust_optimize() {
-    parse("rust.optimize = \"a\"");
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.optimize = \"a\"")
+        .create_config();
 }
 
 #[test]
 fn verify_file_integrity() {
-    let config = parse("");
+    let config = TestCtx::new().config("check").no_dry_run().create_config();
 
     let tempfile = config.tempdir().join(".tmp-test-file");
     File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap();
@@ -292,8 +218,6 @@ fn verify_file_integrity() {
         config
             .verify(&tempfile, "7e255dd9542648a8779268a0f268b891a198e9828e860ed23f826440e786eae5")
     );
-
-    remove_file(tempfile).unwrap();
 }
 
 #[test]
@@ -324,22 +248,23 @@ fn parse_change_id_with_unknown_field() {
 
 #[test]
 fn order_of_clippy_rules() {
-    let args = vec![
-        "clippy".to_string(),
-        "--fix".to_string(),
-        "--allow-dirty".to_string(),
-        "--allow-staged".to_string(),
-        "-Aclippy:all".to_string(),
-        "-Wclippy::style".to_string(),
-        "-Aclippy::foo1".to_string(),
-        "-Aclippy::foo2".to_string(),
+    let args = [
+        "clippy",
+        "--fix",
+        "--allow-dirty",
+        "--allow-staged",
+        "-Aclippy:all",
+        "-Wclippy::style",
+        "-Aclippy::foo1",
+        "-Aclippy::foo2",
     ];
-    let config = Config::parse(Flags::parse(&args));
+    let config = TestCtx::new().config(&args[0]).args(&args[1..]).create_config();
 
     let actual = match config.cmd.clone() {
         crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
             let cfg = LintConfig { allow, deny, warn, forbid };
-            get_clippy_rules_in_order(&args, &cfg)
+            let args_vec: Vec<String> = args.iter().map(|s| s.to_string()).collect();
+            get_clippy_rules_in_order(&args_vec, &cfg)
         }
         _ => panic!("invalid subcommand"),
     };
@@ -356,14 +281,14 @@ fn order_of_clippy_rules() {
 
 #[test]
 fn clippy_rule_separate_prefix() {
-    let args =
-        vec!["clippy".to_string(), "-A clippy:all".to_string(), "-W clippy::style".to_string()];
-    let config = Config::parse(Flags::parse(&args));
+    let args = ["clippy", "-A clippy:all", "-W clippy::style"];
+    let config = TestCtx::new().config(&args[0]).args(&args[1..]).create_config();
 
     let actual = match config.cmd.clone() {
         crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
             let cfg = LintConfig { allow, deny, warn, forbid };
-            get_clippy_rules_in_order(&args, &cfg)
+            let args_vec: Vec<String> = args.iter().map(|s| s.to_string()).collect();
+            get_clippy_rules_in_order(&args_vec, &cfg)
         }
         _ => panic!("invalid subcommand"),
     };
@@ -374,16 +299,20 @@ fn clippy_rule_separate_prefix() {
 
 #[test]
 fn verbose_tests_default_value() {
-    let config = Config::parse(Flags::parse(&["build".into(), "compiler".into()]));
+    let config = TestCtx::new().config("build").args(&["compiler".into()]).create_config();
     assert_eq!(config.verbose_tests, false);
 
-    let config = Config::parse(Flags::parse(&["build".into(), "compiler".into(), "-v".into()]));
+    let config =
+        TestCtx::new().config("build").args(&["compiler".into(), "-v".into()]).create_config();
     assert_eq!(config.verbose_tests, true);
 }
 
 #[test]
 fn parse_rust_std_features() {
-    let config = parse("rust.std-features = [\"panic-unwind\", \"backtrace\"]");
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.std-features = [\"panic-unwind\", \"backtrace\"]")
+        .create_config();
     let expected_features: BTreeSet<String> =
         ["panic-unwind", "backtrace"].into_iter().map(|s| s.to_string()).collect();
     assert_eq!(config.rust_std_features, expected_features);
@@ -391,7 +320,10 @@ fn parse_rust_std_features() {
 
 #[test]
 fn parse_rust_std_features_empty() {
-    let config = parse("rust.std-features = []");
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.std-features = []")
+        .create_config();
     let expected_features: BTreeSet<String> = BTreeSet::new();
     assert_eq!(config.rust_std_features, expected_features);
 }
@@ -399,70 +331,65 @@ fn parse_rust_std_features_empty() {
 #[test]
 #[should_panic]
 fn parse_rust_std_features_invalid() {
-    parse("rust.std-features = \"backtrace\"");
+    TestCtx::new()
+        .config("check")
+        .with_default_toml_config("rust.std-features = \"backtrace\"")
+        .create_config();
 }
 
 #[test]
 fn parse_jobs() {
-    assert_eq!(parse("build.jobs = 1").jobs, Some(1));
+    assert_eq!(
+        TestCtx::new()
+            .config("check")
+            .with_default_toml_config("build.jobs = 1")
+            .create_config()
+            .jobs,
+        Some(1)
+    );
 }
 
 #[test]
 fn jobs_precedence() {
     // `--jobs` should take precedence over using `--set build.jobs`.
 
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--jobs=67890".to_owned(),
-            "--set=build.jobs=12345".to_owned(),
-        ]),
-        |&_| toml::from_str(""),
-    );
+    let config = TestCtx::new()
+        .config("check")
+        .args(&["--jobs=67890", "--set=build.jobs=12345"])
+        .create_config();
     assert_eq!(config.jobs, Some(67890));
 
     // `--set build.jobs` should take precedence over `bootstrap.toml`.
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--set=build.jobs=12345".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
-            [build]
-            jobs = 67890
-        "#,
-            )
-        },
-    );
+    let config = TestCtx::new()
+        .config("check")
+        .args(&["--set=build.jobs=12345"])
+        .with_default_toml_config(
+            r#"
+        [build]
+        jobs = 67890
+    "#,
+        )
+        .create_config();
+
     assert_eq!(config.jobs, Some(12345));
 
     // `--jobs` > `--set build.jobs` > `bootstrap.toml`
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--jobs=123".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-            "--set=build.jobs=456".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
-            [build]
-            jobs = 789
-        "#,
-            )
-        },
-    );
+    let config = TestCtx::new()
+        .config("check")
+        .args(&["--jobs=123", "--set=build.jobs=456"])
+        .with_default_toml_config(
+            r#"
+        [build]
+        jobs = 789
+    "#,
+        )
+        .create_config();
     assert_eq!(config.jobs, Some(123));
 }
 
 #[test]
 fn check_rustc_if_unchanged_paths() {
-    let config = parse("");
+    let config = TestCtx::new().config("check").create_config();
     let normalised_allowed_paths: Vec<_> = RUSTC_IF_UNCHANGED_ALLOWED_PATHS
         .iter()
         .map(|t| {
@@ -477,59 +404,42 @@ fn check_rustc_if_unchanged_paths() {
 
 #[test]
 fn test_explicit_stage() {
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]),
-        |&_| {
-            toml::from_str(
-                r#"
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config(
+            r#"
             [build]
             test-stage = 1
         "#,
-            )
-        },
-    );
+        )
+        .create_config();
 
     assert!(!config.explicit_stage_from_cli);
     assert!(config.explicit_stage_from_config);
     assert!(config.is_explicit_stage());
 
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--stage=2".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-        ]),
-        |&_| toml::from_str(""),
-    );
+    let config = TestCtx::new().config("check").stage(2).create_config();
 
     assert!(config.explicit_stage_from_cli);
     assert!(!config.explicit_stage_from_config);
     assert!(config.is_explicit_stage());
 
-    let config = Config::parse_inner(
-        Flags::parse(&[
-            "check".to_owned(),
-            "--stage=2".to_owned(),
-            "--config=/does/not/exist".to_owned(),
-        ]),
-        |&_| {
-            toml::from_str(
-                r#"
+    let config = TestCtx::new()
+        .config("check")
+        .stage(2)
+        .with_default_toml_config(
+            r#"
             [build]
             test-stage = 1
         "#,
-            )
-        },
-    );
+        )
+        .create_config();
 
     assert!(config.explicit_stage_from_cli);
     assert!(config.explicit_stage_from_config);
     assert!(config.is_explicit_stage());
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]),
-        |&_| toml::from_str(""),
-    );
+    let config = TestCtx::new().config("check").create_config();
 
     assert!(!config.explicit_stage_from_cli);
     assert!(!config.explicit_stage_from_config);
@@ -539,7 +449,10 @@ fn test_explicit_stage() {
 #[test]
 fn test_exclude() {
     let exclude_path = "compiler";
-    let config = parse(&format!("build.exclude=[\"{}\"]", exclude_path));
+    let config = TestCtx::new()
+        .config("check")
+        .with_default_toml_config(&format!("build.exclude=[\"{}\"]", exclude_path))
+        .create_config();
 
     let first_excluded = config
         .skip
@@ -553,32 +466,20 @@ fn test_exclude() {
 
 #[test]
 fn test_ci_flag() {
-    let config = Config::parse_inner(Flags::parse(&["check".into(), "--ci=false".into()]), |&_| {
-        toml::from_str("")
-    });
+    let config = TestCtx::new().config("check").arg("--ci").arg("false").create_config();
     assert!(!config.is_running_on_ci);
 
-    let config = Config::parse_inner(Flags::parse(&["check".into(), "--ci=true".into()]), |&_| {
-        toml::from_str("")
-    });
+    let config = TestCtx::new().config("check").arg("--ci").arg("true").create_config();
     assert!(config.is_running_on_ci);
 
-    let config = Config::parse_inner(Flags::parse(&["check".into()]), |&_| toml::from_str(""));
+    let config = TestCtx::new().config("check").create_config();
     assert_eq!(config.is_running_on_ci, CiEnv::is_ci());
 }
 
 #[test]
 fn test_precedence_of_includes() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./extension.toml"]
-
-        [llvm]
-        link-jobs = 2
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
@@ -599,10 +500,17 @@ fn test_precedence_of_includes() {
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    let config = test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./extension.toml"]
+
+        [llvm]
+        link-jobs = 2
+    "#,
+        )
+        .create_config();
 
     assert_eq!(config.change_id.unwrap(), ChangeId::Id(543));
     assert_eq!(config.llvm_link_jobs.unwrap(), 2);
@@ -612,36 +520,29 @@ fn test_precedence_of_includes() {
 #[test]
 #[should_panic(expected = "Cyclic inclusion detected")]
 fn test_cyclic_include_direct() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
-
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
-        include = ["./config.toml"]
+        include = ["./bootstrap.toml"]
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./extension.toml"]
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
 #[should_panic(expected = "Cyclic inclusion detected")]
 fn test_cyclic_include_indirect() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
@@ -661,43 +562,37 @@ fn test_cyclic_include_indirect() {
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./extension.toml"]
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
 fn test_include_absolute_paths() {
-    let testdir = prepare_test_specific_dir();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     File::create(&extension).unwrap().write_all(&[]).unwrap();
 
-    let root_config = testdir.join("config.toml");
     let extension_absolute_path =
         extension.canonicalize().unwrap().to_str().unwrap().replace('\\', r"\\");
     let root_config_content = format!(r#"include = ["{}"]"#, extension_absolute_path);
-    File::create(&root_config).unwrap().write_all(root_config_content.as_bytes()).unwrap();
-
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx.config("check").with_default_toml_config(&root_config_content).create_config();
 }
 
 #[test]
 fn test_include_relative_paths() {
-    let testdir = prepare_test_specific_dir();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let _ = fs::create_dir_all(&testdir.join("subdir/another_subdir"));
 
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        include = ["./subdir/extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
-
     let extension = testdir.join("subdir/extension.toml");
     let extension_content = br#"
         include = ["../extension2.toml"]
@@ -719,22 +614,20 @@ fn test_include_relative_paths() {
     let extension = testdir.join("extension4.toml");
     File::create(extension).unwrap().write_all(&[]).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        include = ["./subdir/extension.toml"]
+    "#,
+        )
+        .create_config();
 }
 
 #[test]
 fn test_include_precedence_over_profile() {
-    let testdir = prepare_test_specific_dir();
-
-    let root_config = testdir.join("config.toml");
-    let root_config_content = br#"
-        profile = "dist"
-        include = ["./extension.toml"]
-    "#;
-    File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+    let test_ctx = TestCtx::new();
+    let testdir = test_ctx.dir();
 
     let extension = testdir.join("extension.toml");
     let extension_content = br#"
@@ -743,10 +636,15 @@ fn test_include_precedence_over_profile() {
     "#;
     File::create(extension).unwrap().write_all(extension_content).unwrap();
 
-    let config = Config::parse_inner(
-        Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
-        get_toml,
-    );
+    let config = test_ctx
+        .config("check")
+        .with_default_toml_config(
+            r#"
+        profile = "dist"
+        include = ["./extension.toml"]
+    "#,
+        )
+        .create_config();
 
     // "dist" profile would normally set the channel to "auto-detect", but includes should
     // override profile settings, so we expect this to be "dev" here.
diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs
index 7af22432ef8..f6dc5b67e10 100644
--- a/src/bootstrap/src/core/config/toml/mod.rs
+++ b/src/bootstrap/src/core/config/toml/mod.rs
@@ -152,10 +152,6 @@ impl Config {
     }
 
     pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
-        #[cfg(test)]
-        return Ok(TomlConfig::default());
-
-        #[cfg(not(test))]
         Self::get_toml_inner(file)
     }
 
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 2f3c80559c0..37871f0fe1e 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -106,7 +106,7 @@ enum DownloadSource {
 /// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions.
 impl Config {
     pub(crate) fn download_clippy(&self) -> PathBuf {
-        self.verbose(|| println!("downloading stage0 clippy artifacts"));
+        self.do_if_verbose(|| println!("downloading stage0 clippy artifacts"));
 
         let date = &self.stage0_metadata.compiler.date;
         let version = &self.stage0_metadata.compiler.version;
@@ -151,7 +151,9 @@ impl Config {
     }
 
     pub(crate) fn download_ci_rustc(&self, commit: &str) {
-        self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})"));
+        self.do_if_verbose(|| {
+            println!("using downloaded stage2 artifacts from CI (commit {commit})")
+        });
 
         let version = self.artifact_version_part(commit);
         // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the
@@ -258,7 +260,7 @@ impl Config {
         let llvm_root = self.ci_llvm_root();
         let llvm_freshness =
             detect_llvm_freshness(self, self.rust_info.is_managed_git_subrepository());
-        self.verbose(|| {
+        self.do_if_verbose(|| {
             eprintln!("LLVM freshness: {llvm_freshness:?}");
         });
         let llvm_sha = match llvm_freshness {
@@ -557,7 +559,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a
 #[cfg(not(test))]
 pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, out: &Path) {
     let dwn_ctx = dwn_ctx.as_ref();
-    dwn_ctx.exec_ctx.verbose(|| {
+    dwn_ctx.exec_ctx.do_if_verbose(|| {
         println!("downloading stage0 beta artifacts");
     });
 
@@ -812,7 +814,7 @@ fn download_component<'a>(
                 unpack(dwn_ctx.exec_ctx, &tarball, &bin_root, prefix);
                 return;
             } else {
-                dwn_ctx.exec_ctx.verbose(|| {
+                dwn_ctx.exec_ctx.do_if_verbose(|| {
                     println!(
                         "ignoring cached file {} due to failed verification",
                         tarball.display()
@@ -853,7 +855,7 @@ download-rustc = false
 pub(crate) fn verify(exec_ctx: &ExecutionContext, path: &Path, expected: &str) -> bool {
     use sha2::Digest;
 
-    exec_ctx.verbose(|| {
+    exec_ctx.do_if_verbose(|| {
         println!("verifying {}", path.display());
     });
 
@@ -934,7 +936,7 @@ fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str
         short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
         let dst_path = dst.join(short_path);
 
-        exec_ctx.verbose(|| {
+        exec_ctx.do_if_verbose(|| {
             println!("extracting {} to {}", original_path.display(), dst.display());
         });
 
@@ -965,7 +967,7 @@ fn download_file<'a>(
 ) {
     let dwn_ctx = dwn_ctx.as_ref();
 
-    dwn_ctx.exec_ctx.verbose(|| {
+    dwn_ctx.exec_ctx.do_if_verbose(|| {
         println!("download {url}");
     });
     // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 68202500d97..91d80c96e42 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -38,6 +38,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
     "aarch64_be-unknown-hermit",
     "aarch64_be-unknown-none-softfloat",
+    "x86_64-unknown-motor",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
@@ -239,6 +240,10 @@ than building it.
             continue;
         }
 
+        if target.contains("motor") {
+            continue;
+        }
+
         // skip check for cross-targets
         if skip_target_sanity && target != &build.host_target {
             continue;
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index e953fe2945e..4f4d35673d5 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -415,7 +415,7 @@ macro_rules! forward {
 }
 
 forward! {
-    verbose(f: impl Fn()),
+    do_if_verbose(f: impl Fn()),
     is_verbose() -> bool,
     create(path: &Path, s: &str),
     remove(f: &Path),
@@ -601,11 +601,11 @@ impl Build {
             .unwrap()
             .trim();
         if local_release.split('.').take(2).eq(version.split('.').take(2)) {
-            build.verbose(|| println!("auto-detected local-rebuild {local_release}"));
+            build.do_if_verbose(|| println!("auto-detected local-rebuild {local_release}"));
             build.local_rebuild = true;
         }
 
-        build.verbose(|| println!("finding compilers"));
+        build.do_if_verbose(|| println!("finding compilers"));
         utils::cc_detect::fill_compilers(&mut build);
         // When running `setup`, the profile is about to change, so any requirements we have now may
         // be different on the next invocation. Don't check for them until the next time x.py is
@@ -613,7 +613,7 @@ impl Build {
         //
         // Similarly, for `setup` we don't actually need submodules or cargo metadata.
         if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
-            build.verbose(|| println!("running sanity check"));
+            build.do_if_verbose(|| println!("running sanity check"));
             crate::core::sanity::check(&mut build);
 
             // Make sure we update these before gathering metadata so we don't get an error about missing
@@ -631,7 +631,7 @@ impl Build {
             // Now, update all existing submodules.
             build.update_existing_submodules();
 
-            build.verbose(|| println!("learning about cargo"));
+            build.do_if_verbose(|| println!("learning about cargo"));
             crate::core::metadata::build(&mut build);
         }
 
@@ -1087,18 +1087,6 @@ impl Build {
         })
     }
 
-    /// Check if verbosity is greater than the `level`
-    pub fn is_verbose_than(&self, level: usize) -> bool {
-        self.verbosity > level
-    }
-
-    /// Runs a function if verbosity is greater than `level`.
-    fn verbose_than(&self, level: usize, f: impl Fn()) {
-        if self.is_verbose_than(level) {
-            f()
-        }
-    }
-
     fn info(&self, msg: &str) {
         match self.config.get_dry_run() {
             DryRun::SelfCheck => (),
@@ -1816,7 +1804,6 @@ impl Build {
         if self.config.dry_run() {
             return;
         }
-        self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}"));
         if src == dst {
             return;
         }
@@ -1933,7 +1920,10 @@ impl Build {
             return;
         }
         let dst = dstdir.join(src.file_name().unwrap());
-        self.verbose_than(1, || println!("Install {src:?} to {dst:?}"));
+
+        #[cfg(feature = "tracing")]
+        let _span = trace_io!("install", ?src, ?dst);
+
         t!(fs::create_dir_all(dstdir));
         if !src.exists() {
             panic!("ERROR: File \"{}\" not found!", src.display());
diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs
index 4c35388a181..5cd68f6d4fe 100644
--- a/src/bootstrap/src/utils/build_stamp.rs
+++ b/src/bootstrap/src/utils/build_stamp.rs
@@ -112,7 +112,7 @@ pub fn clear_if_dirty(builder: &Builder<'_>, dir: &Path, input: &Path) -> bool {
     let stamp = BuildStamp::new(dir);
     let mut cleared = false;
     if mtime(stamp.path()) < mtime(input) {
-        builder.verbose(|| println!("Dirty - {}", dir.display()));
+        builder.do_if_verbose(|| println!("Dirty - {}", dir.display()));
         let _ = fs::remove_dir_all(dir);
         cleared = true;
     } else if stamp.path().exists() {
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index d3926df9650..0662ae304ac 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -137,16 +137,16 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) {
         build.cxx.insert(target, compiler);
     }
 
-    build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
-    build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
+    build.do_if_verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
+    build.do_if_verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
     if let Ok(cxx) = build.cxx(target) {
         let mut cxxflags = build.cc_handled_clags(target, CLang::Cxx);
         cxxflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx));
-        build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
-        build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
+        build.do_if_verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
+        build.do_if_verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
     }
     if let Some(ar) = ar {
-        build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
+        build.do_if_verbose(|| println!("AR_{} = {ar:?}", target.triple));
         build.ar.insert(target, ar);
     }
 
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index e09f3086b77..f875e6e1af7 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -630,7 +630,7 @@ impl ExecutionContext {
         &self.dry_run
     }
 
-    pub fn verbose(&self, f: impl Fn()) {
+    pub fn do_if_verbose(&self, f: impl Fn()) {
         if self.is_verbose() {
             f()
         }
@@ -686,7 +686,7 @@ impl ExecutionContext {
 
         if let Some(cached_output) = self.command_cache.get(&fingerprint) {
             command.mark_as_executed();
-            self.verbose(|| println!("Cache hit: {command:?}"));
+            self.do_if_verbose(|| println!("Cache hit: {command:?}"));
             self.profiler.record_cache_hit(fingerprint);
             return DeferredCommand { state: CommandState::Cached(cached_output) };
         }
@@ -713,7 +713,7 @@ impl ExecutionContext {
             };
         }
 
-        self.verbose(|| {
+        self.do_if_verbose(|| {
             println!("running: {command:?} (created at {created_at}, executed at {executed_at})")
         });
 
diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs
index 9030ca2820a..676fe6cbd5f 100644
--- a/src/bootstrap/src/utils/helpers/tests.rs
+++ b/src/bootstrap/src/utils/helpers/tests.rs
@@ -6,6 +6,7 @@ use crate::utils::helpers::{
     check_cfg_arg, extract_beta_rev, hex_encode, make, set_file_times, submodule_path_of,
     symlink_dir,
 };
+use crate::utils::tests::TestCtx;
 use crate::{Config, Flags};
 
 #[test]
@@ -59,8 +60,7 @@ fn test_check_cfg_arg() {
 
 #[test]
 fn test_symlink_dir() {
-    let config =
-        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
+    let config = TestCtx::new().config("check").no_dry_run().create_config();
     let tempdir = config.tempdir().join(".tmp-dir");
     let link_path = config.tempdir().join(".tmp-link");
 
@@ -80,8 +80,7 @@ fn test_symlink_dir() {
 
 #[test]
 fn test_set_file_times_sanity_check() {
-    let config =
-        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
+    let config = TestCtx::new().config("check").create_config();
     let tempfile = config.tempdir().join(".tmp-file");
 
     {
@@ -102,9 +101,7 @@ fn test_set_file_times_sanity_check() {
 
 #[test]
 fn test_submodule_path_of() {
-    let config = Config::parse_inner(Flags::parse(&["build".into(), "--dry-run".into()]), |&_| {
-        Ok(Default::default())
-    });
+    let config = TestCtx::new().config("build").create_config();
 
     let build = crate::Build::new(config.clone());
     let builder = crate::core::builder::Builder::new(&build);
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 90fd57d976d..e90a7ef4232 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -48,7 +48,7 @@ pub(crate) fn try_run_tests(
 }
 
 fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool {
-    builder.verbose(|| println!("running: {cmd:?}"));
+    builder.do_if_verbose(|| println!("running: {cmd:?}"));
 
     let Some(mut streaming_command) = cmd.stream_capture_stdout(&builder.config.exec_ctx) else {
         return true;
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 7b77b212934..079afb7a005 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -356,7 +356,7 @@ impl<'a> Tarball<'a> {
 
         // For `x install` tarball files aren't needed, so we can speed up the process by not producing them.
         let compression_profile = if self.builder.kind == Kind::Install {
-            self.builder.verbose(|| {
+            self.builder.do_if_verbose(|| {
                 println!("Forcing dist.compression-profile = 'no-op' for `x install`.")
             });
             // "no-op" indicates that the rust-installer won't produce compressed tarball sources.
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
index 3332187e2a8..764b89086cf 100644
--- a/src/bootstrap/src/utils/tests/mod.rs
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -48,11 +48,20 @@ impl TestCtx {
 pub struct ConfigBuilder {
     args: Vec<String>,
     directory: PathBuf,
+    override_download_ci_llvm: bool,
+    dry_run: bool,
+    explicit_config: bool,
 }
 
 impl ConfigBuilder {
     fn from_args(args: &[&str], directory: PathBuf) -> Self {
-        Self { args: args.iter().copied().map(String::from).collect(), directory }
+        Self {
+            args: args.iter().copied().map(String::from).collect(),
+            directory,
+            override_download_ci_llvm: true,
+            dry_run: true,
+            explicit_config: true,
+        }
     }
 
     pub fn path(mut self, path: &str) -> Self {
@@ -98,18 +107,46 @@ impl ConfigBuilder {
         self
     }
 
-    pub fn create_config(mut self) -> Config {
-        // Run in dry-check, otherwise the test would be too slow
-        self.args.push("--dry-run".to_string());
+    pub fn with_default_toml_config(mut self, config_toml: &str) -> Self {
+        let toml_path = self.directory.join("bootstrap.toml");
+        std::fs::write(&toml_path, config_toml).unwrap();
+        self.explicit_config = false;
+        self.args.push("--config".to_string());
+        self.args.push(toml_path.display().to_string());
+        self
+    }
+
+    pub fn no_override_download_ci_llvm(mut self) -> Self {
+        self.override_download_ci_llvm = false;
+        self
+    }
+
+    pub fn no_dry_run(mut self) -> Self {
+        self.dry_run = false;
+        self
+    }
 
+    pub fn create_config(mut self) -> Config {
+        if self.dry_run {
+            // Run in dry-check, otherwise the test would be too slow
+            self.args.push("--dry-run".to_string());
+        }
         // Ignore submodules
         self.args.push("--set".to_string());
         self.args.push("build.submodules=false".to_string());
 
-        // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building
-        // in-tree LLVM from sources.
-        self.args.push("--set".to_string());
-        self.args.push("llvm.download-ci-llvm=false".to_string());
+        if self.override_download_ci_llvm {
+            // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building
+            // in-tree LLVM from sources.
+            self.args.push("--set".to_string());
+            self.args.push("llvm.download-ci-llvm=false".to_string());
+        }
+
+        // always use the bootstrap toml created in the
+        // temporary directory and not from the <src>
+        if self.explicit_config {
+            self = self.with_default_toml_config("");
+        }
 
         // Do not mess with the local rustc checkout build directory
         self.args.push("--build-dir".to_string());
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
index 71de8f917fa..04b46226acf 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:25.10
 
 ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile
index adbb1f03378..095624d6fb7 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:25.04
+FROM ubuntu:25.10
 
 ARG DEBIAN_FRONTEND=noninteractive
 
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
index e6133fce83e..4b61fd94a6c 100644
--- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
+++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ubuntu:25.10
 
 ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
index ff9fedad656..14cf63b94d4 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
@@ -30,3 +30,10 @@ cat /tmp/toolstate/toolstates.json
 python3 "$X_PY" test --stage 2 check-tools
 python3 "$X_PY" test --stage 2 src/tools/clippy
 python3 "$X_PY" test --stage 2 src/tools/rustfmt
+
+# The below is a regression test for https://github.com/rust-lang/rust/pull/146501#issuecomment-3292608398.
+# The bug caused 0 tests to run. By grepping on that 1 test is run we prevent regressing.
+# Any test can be used. We arbitrarily chose `tests/ui/lint/unused/unused-result.rs`.
+python3 "$X_PY" test tests/ui --test-args tests/ui/lint/unused/unused-result.rs --force-rerun |
+grep --fixed-strings 'test result: ok. 1 passed; 0 failed; 0 ignored;' ||
+( echo "ERROR: --test-args functionality is broken" && exit 1 )
diff --git a/src/doc/book b/src/doc/book
-Subproject 3e9dc46aa563ca0c53ec826c41b05f10c591592
+Subproject 33f1af40cc44dde7e3e892f7a508e6f427d2cbc
diff --git a/src/doc/reference b/src/doc/reference
-Subproject b3ce60628c6f55ab8ff3dba9f3d20203df1c0de
+Subproject cc7247d8dfaef4c39000bb12c55c32ba5b5ba97
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject dd26bc8e726dc2e73534c8972d4dccd1bed7495
+Subproject 2c9b490d70e535cf166bf17feba59e594579843
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index df2bac877b6..0dc9ce843e9 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-2f3f27bf79ec147fec9d2e7980605307a74067f4
+9f32ccf35fb877270bc44a86a126440f04d676d0
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index a1612738537..249140956c0 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -108,6 +108,7 @@
     - [Installation](./autodiff/installation.md)
     - [How to debug](./autodiff/debugging.md)
     - [Autodiff flags](./autodiff/flags.md)
+    - [Type Trees](./autodiff/type-trees.md)
 
 # Source Code Representation
 
diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md
index f1a406a1c29..4f5733ae082 100644
--- a/src/doc/rustc-dev-guide/src/about-this-guide.md
+++ b/src/doc/rustc-dev-guide/src/about-this-guide.md
@@ -48,9 +48,9 @@ In addition, many of the ideas discussed throughout this guide are idealized des
 that are not fully realized yet.
 All this makes keeping this guide completely up to date on everything very hard!
 
-The Guide itself is of course open-source as well,
-and the sources can be found at the [GitHub repository].
-If you find any mistakes in the guide, please file an issue about it.
+The guide itself is of course open source as well,
+and the sources are hosted on [a GitHub repository].
+If you find any mistakes in the guide, please file an issue.
 Even better, open a PR with a correction!
 
 If you do contribute to the guide,
@@ -105,7 +105,7 @@ You might also find the following sites useful:
 [cheatsheet]: https://bors.rust-lang.org/
 [Miri]: https://github.com/rust-lang/miri
 [@bors]: https://github.com/bors
-[GitHub repository]: https://github.com/rust-lang/rustc-dev-guide/
+[a GitHub repository]: https://github.com/rust-lang/rustc-dev-guide/
 [rustc API docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle
 [Forge]: https://forge.rust-lang.org/
 [compiler-team]: https://github.com/rust-lang/compiler-team/
diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md
index 1837b59e850..21162f8ee7d 100644
--- a/src/doc/rustc-dev-guide/src/appendix/glossary.md
+++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md
@@ -68,6 +68,7 @@ Term                                                  | Meaning
 <span id="rib">rib</span>                      |  A data structure in the name resolver that keeps track of a single scope for names. ([see more](../name-resolution.md))
 <span id="rpit">RPIT</span>                    |  A return-position `impl Trait`. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types)).
 <span id="rpitit">RPITIT</span>                |  A return-position `impl Trait` in trait. Unlike RPIT, this is desugared to a generic associated type (GAT). Introduced in [RFC 3425](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). ([see more](../return-position-impl-trait-in-trait.md))
+<span id="rustbuild">rustbuild</span>          |  A deprecated term for the part of bootstrap that is written in Rust
 <span id="scrutinee">scrutinee</span>          |  A scrutinee is the expression that is matched on in `match` expressions and similar pattern matching constructs. For example, in `match x { A => 1, B => 2 }`, the expression `x` is the scrutinee.
 <span id="sess">`sess`</span>                  |  The compiler _session_, which stores global data used throughout compilation
 <span id="side-tables">side tables</span>      |  Because the [AST](#ast) and HIR are immutable once created, we often carry extra information about them in the form of hashtables, indexed by the id of a particular node.
diff --git a/src/doc/rustc-dev-guide/src/autodiff/type-trees.md b/src/doc/rustc-dev-guide/src/autodiff/type-trees.md
new file mode 100644
index 00000000000..68cb78650b0
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/autodiff/type-trees.md
@@ -0,0 +1,193 @@
+# TypeTrees for Autodiff
+
+## What are TypeTrees?
+Memory layout descriptors for Enzyme. Tell Enzyme exactly how types are structured in memory so it can compute derivatives efficiently.
+
+## Structure
+```rust
+TypeTree(Vec<Type>)
+
+Type {
+    offset: isize,  // byte offset (-1 = everywhere)
+    size: usize,    // size in bytes
+    kind: Kind,     // Float, Integer, Pointer, etc.
+    child: TypeTree // nested structure
+}
+```
+
+## Example: `fn compute(x: &f32, data: &[f32]) -> f32`
+
+**Input 0: `x: &f32`**
+```rust
+TypeTree(vec![Type {
+    offset: -1, size: 8, kind: Pointer,
+    child: TypeTree(vec![Type {
+        offset: 0, size: 4, kind: Float,  // Single value: use offset 0
+        child: TypeTree::new()
+    }])
+}])
+```
+
+**Input 1: `data: &[f32]`**
+```rust
+TypeTree(vec![Type {
+    offset: -1, size: 8, kind: Pointer,
+    child: TypeTree(vec![Type {
+        offset: -1, size: 4, kind: Float,  // -1 = all elements
+        child: TypeTree::new()
+    }])
+}])
+```
+
+**Output: `f32`**
+```rust
+TypeTree(vec![Type {
+    offset: 0, size: 4, kind: Float,  // Single scalar: use offset 0
+    child: TypeTree::new()
+}])
+```
+
+## Why Needed?
+- Enzyme can't deduce complex type layouts from LLVM IR
+- Prevents slow memory pattern analysis
+- Enables correct derivative computation for nested structures
+- Tells Enzyme which bytes are differentiable vs metadata
+
+## What Enzyme Does With This Information:
+
+Without TypeTrees:
+```llvm
+; Enzyme sees generic LLVM IR:
+define float @distance(ptr %p1, ptr %p2) {
+; Has to guess what these pointers point to
+; Slow analysis of all memory operations
+; May miss optimization opportunities
+}
+```
+
+With TypeTrees:
+```llvm
+define "enzyme_type"="{[-1]:Float@float}" float @distance(
+    ptr "enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float}" %p1, 
+    ptr "enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float}" %p2
+) {
+; Enzyme knows exact type layout
+; Can generate efficient derivative code directly
+}
+```
+
+# TypeTrees - Offset and -1 Explained
+
+## Type Structure
+
+```rust
+Type {
+    offset: isize, // WHERE this type starts
+    size: usize,   // HOW BIG this type is
+    kind: Kind,    // WHAT KIND of data (Float, Int, Pointer)
+    child: TypeTree // WHAT'S INSIDE (for pointers/containers)
+}
+```
+
+## Offset Values
+
+### Regular Offset (0, 4, 8, etc.)
+**Specific byte position within a structure**
+
+```rust
+struct Point {
+    x: f32, // offset 0, size 4
+    y: f32, // offset 4, size 4
+    id: i32, // offset 8, size 4
+}
+```
+
+TypeTree for `&Point` (internal representation):
+```rust
+TypeTree(vec![
+    Type { offset: 0, size: 4, kind: Float },   // x at byte 0
+    Type { offset: 4, size: 4, kind: Float },   // y at byte 4
+    Type { offset: 8, size: 4, kind: Integer }  // id at byte 8
+])
+```
+
+Generates LLVM
+```llvm
+"enzyme_type"="{[-1]:Pointer, [-1,0]:Float@float, [-1,4]:Float@float, [-1,8]:Integer, [-1,9]:Integer, [-1,10]:Integer, [-1,11]:Integer}"
+```
+
+### Offset -1 (Special: "Everywhere")
+**Means "this pattern repeats for ALL elements"**
+
+#### Example 1: Direct Array `[f32; 100]` (no pointer indirection)
+```rust
+TypeTree(vec![Type {
+    offset: -1, // ALL positions
+    size: 4,    // each f32 is 4 bytes
+    kind: Float, // every element is float
+}])
+```
+
+Generates LLVM: `"enzyme_type"="{[-1]:Float@float}"`
+
+#### Example 1b: Array Reference `&[f32; 100]` (with pointer indirection)  
+```rust
+TypeTree(vec![Type {
+    offset: -1, size: 8, kind: Pointer,
+    child: TypeTree(vec![Type {
+        offset: -1, // ALL array elements
+        size: 4,    // each f32 is 4 bytes
+        kind: Float, // every element is float
+    }])
+}])
+```
+
+Generates LLVM: `"enzyme_type"="{[-1]:Pointer, [-1,-1]:Float@float}"`
+
+Instead of listing 100 separate Types with offsets `0,4,8,12...396`
+
+#### Example 2: Slice `&[i32]`
+```rust
+// Pointer to slice data
+TypeTree(vec![Type {
+    offset: -1, size: 8, kind: Pointer,
+    child: TypeTree(vec![Type {
+        offset: -1, // ALL slice elements
+        size: 4,    // each i32 is 4 bytes
+        kind: Integer
+    }])
+}])
+```
+
+Generates LLVM: `"enzyme_type"="{[-1]:Pointer, [-1,-1]:Integer}"`
+
+#### Example 3: Mixed Structure
+```rust
+struct Container {
+    header: i64,        // offset 0
+    data: [f32; 1000],  // offset 8, but elements use -1
+}
+```
+
+```rust
+TypeTree(vec![
+    Type { offset: 0, size: 8, kind: Integer }, // header
+    Type { offset: 8, size: 4000, kind: Pointer,
+        child: TypeTree(vec![Type {
+            offset: -1, size: 4, kind: Float // ALL array elements
+        }])
+    }
+])
+```
+
+## Key Distinction: Single Values vs Arrays
+
+**Single Values** use offset `0` for precision:
+- `&f32` has exactly one f32 value at offset 0
+- More precise than using -1 ("everywhere")  
+- Generates: `{[-1]:Pointer, [-1,0]:Float@float}`
+
+**Arrays** use offset `-1` for efficiency:
+- `&[f32; 100]` has the same pattern repeated 100 times
+- Using -1 avoids listing 100 separate offsets
+- Generates: `{[-1]:Pointer, [-1,-1]:Float@float}`
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md
index c3660e24b15..8ac2e6bfe28 100644
--- a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md
@@ -3,18 +3,32 @@
 There are three types of tools you can write in bootstrap:
 
 - **`Mode::ToolBootstrap`**
+
   Use this for tools that don’t need anything from the in-tree compiler and can run with the stage0 `rustc`.
-  The output is placed in the "bootstrap-tools" directory. This mode is for general-purpose tools built
-  entirely with the stage0 compiler, including target libraries and only works for stage 0.
+  The output is placed in the "bootstrap-tools" directory.
+  This mode is for general-purpose tools built entirely with the stage0 compiler,
+  including target libraries, and it only works for stage 0.
 
 - **`Mode::ToolStd`**
-  Use this for tools that rely on the locally built std. The output goes into the "stageN-tools" directory.
+
+  Use this for tools that rely on the locally built std.
+  The output goes into the "stageN-tools" directory.
   This mode is rarely used, mainly for `compiletest` which requires `libtest`.
 
 - **`Mode::ToolRustcPrivate`**
-  Use this for tools that use the `rustc_private` mechanism, and thus depend on the locally built `rustc` and its rlib artifacts. This is more complex than the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools" directory. When you choose `Mode::ToolRustcPrivate`, `ToolBuild` implementation takes care of this automatically. If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is
-  returned by the tool's [`Step`].
 
-Regardless of the tool type you must return `ToolBuildResult` from the tool’s [`Step`] implementation and use `ToolBuild` inside it.
+  Use this for tools that use the `rustc_private` mechanism,
+  and thus depend on the locally built `rustc` and its rlib artifacts.
+  This is more complex than the other modes,
+  because the tool must be built with the same compiler used for `rustc`,
+  and placed in the "stageN-tools" directory.
+  When you choose `Mode::ToolRustcPrivate`,
+  `ToolBuild` implementation takes care of this automatically.
+  If you need to use the builder’s compiler for something specific,
+  you can get it from `ToolBuildResult`, which is returned by the tool's [`Step`].
+
+Regardless of the tool type,
+you must return `ToolBuildResult` from the tool’s [`Step`] implementation,
+and use `ToolBuild` inside it.
 
 [`Step`]: https://doc.rust-lang.org/nightly/nightly-rustc/bootstrap/core/builder/trait.Step.html
diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
index b07d3533f59..36610f28854 100644
--- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
+++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md
@@ -149,7 +149,7 @@ On Windows, the Powershell commands may give you an error that looks like this:
 ```
 PS C:\Users\vboxuser\rust> ./x
 ./x : File C:\Users\vboxuser\rust\x.ps1 cannot be loaded because running scripts is disabled on this system. For more
-information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
+information, see about_Execution_Policies at https://go.microsoft.com/fwlink/?LinkID=135170.
 At line:1 char:1
 + ./x
 + ~~~
diff --git a/src/doc/rustc-dev-guide/src/compiler-team.md b/src/doc/rustc-dev-guide/src/compiler-team.md
index 6be52833f39..896d9e6f6d9 100644
--- a/src/doc/rustc-dev-guide/src/compiler-team.md
+++ b/src/doc/rustc-dev-guide/src/compiler-team.md
@@ -1,10 +1,14 @@
 # About the compiler team
 
+> NOTE:
+> There exists much detail about the team [on Forge], making most of the following obsolete.
+
 rustc is maintained by the [Rust compiler team][team]. The people who belong to
 this team collectively work to track regressions and implement new features.
 Members of the Rust compiler team are people who have made significant
 contributions to rustc and its design.
 
+[on Forge]: https://forge.rust-lang.org/compiler
 [team]: https://www.rust-lang.org/governance/teams/compiler
 
 ## Discussion
diff --git a/src/doc/rustc-dev-guide/src/fuzzing.md b/src/doc/rustc-dev-guide/src/fuzzing.md
index 30005378617..cc98b49a97c 100644
--- a/src/doc/rustc-dev-guide/src/fuzzing.md
+++ b/src/doc/rustc-dev-guide/src/fuzzing.md
@@ -90,14 +90,15 @@ Here are a few things you can do to help the Rust project after filing an ICE.
   triggering the ICE, such as syntax errors or borrow-checking errors
 - Minimize the test case (see below). If successful, you can label the
   issue with `S-has-mcve`. Otherwise, you can apply `E-needs-mcve`.
-- Add the minimal test case to the rust-lang/rust repo as a [crashes test].
+- Add the minimal test case to the rust-lang/rust repo as a [crash test].
   While you're at it, consider including other "untracked" crashes in your PR.
-  Please don't forget to mark your issue with `S-bug-has-test` afterwards.
+  Please don't forget to mark all relevant issues with `S-bug-has-test` once
+  your PR is merged.
 
 See also [applying and removing labels][labeling].
 
 [bisect]: https://rust-lang.github.io/cargo-bisect-rustc/
-[crashes test]: tests/compiletest.html#crashes-tests
+[crash test]: tests/compiletest.html#crash-tests
 [labeling]: https://forge.rust-lang.org/release/issue-triaging.html#applying-and-removing-labels
 
 ## Minimization
diff --git a/src/doc/rustc-dev-guide/src/profiling/with_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_perf.md
index 0d4f23bcd9a..e452dde5226 100644
--- a/src/doc/rustc-dev-guide/src/profiling/with_perf.md
+++ b/src/doc/rustc-dev-guide/src/profiling/with_perf.md
@@ -4,8 +4,7 @@ This is a guide for how to profile rustc with [perf](https://perf.wiki.kernel.or
 
 ## Initial steps
 
-- Get a clean checkout of rust-lang/master, or whatever it is you want
-  to profile.
+- Get a clean checkout of rust-lang/rust
 - Set the following settings in your `bootstrap.toml`:
   - `rust.debuginfo-level = 1` - enables line debuginfo
   - `rust.jemalloc = false` - lets you do memory use profiling with valgrind
diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md
index efc626035b7..10372c36ac9 100644
--- a/src/doc/rustc-dev-guide/src/tests/best-practices.md
+++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md
@@ -71,7 +71,7 @@ related tests.
 > //! Regression test for <https://github.com/rust-lang/rust/issues/123456>.
 > ```
 >
-> One exception to this rule is [crashes tests]: there it is canonical that
+> One exception to this rule is [crash tests]: there it is canonical that
 > tests are named only after issue numbers because its purpose is to track
 > snippets from which issues no longer ICE/crash, and they would either be
 > removed or converted into proper ui/other tests in the fix PRs.
@@ -199,4 +199,4 @@ See [LLVM FileCheck guide][FileCheck] for details.
 [compiletest directives]: ./directives.md
 [`run-make`]: ./compiletest.md#run-make-tests
 [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html
-[crashes tests]: ./compiletest.md#crashes-tests
+[crash tests]: ./compiletest.md#crash-tests
diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md
index a8cc959124f..6c0b5c2e845 100644
--- a/src/doc/rustc-dev-guide/src/tests/ci.md
+++ b/src/doc/rustc-dev-guide/src/tests/ci.md
@@ -1,18 +1,18 @@
 # Testing with CI
 
 The primary goal of our CI system is to ensure that the `master` branch of
-`rust-lang/rust` is always in a valid state and passes our test suite.
+`rust-lang/rust` is always in a valid state by passing our test suite.
 
 From a high-level point of view, when you open a pull request at
 `rust-lang/rust`, the following will happen:
 
 - A small [subset](#pull-request-builds) of tests and checks are run after each
-  push to the PR. This should help catching common errors.
+  push to the PR. This should help catch common errors.
 - When the PR is approved, the [bors] bot enqueues the PR into a [merge queue].
 - Once the PR gets to the front of the queue, bors will create a merge commit
   and run the [full test suite](#auto-builds) on it. The merge commit either
   contains only one specific PR or it can be a ["rollup"](#rollups) which
-  combines multiple PRs together, to save CI costs.
+  combines multiple PRs together, to reduce CI costs and merge delays.
 - Once the whole test suite finishes, two things can happen. Either CI fails
   with an error that needs to be addressed by the developer, or CI succeeds and
   the merge commit is then pushed to the `master` branch.
@@ -38,12 +38,12 @@ input, which contains a declarative configuration of all our CI jobs.
 > orchestrating the scripts that drive the process.
 
 In essence, all CI jobs run `./x test`, `./x dist` or some other command with
-different configurations, across various operating systems, targets and
+different configurations, across various operating systems, targets, and
 platforms. There are two broad categories of jobs that are executed, `dist` and
 non-`dist` jobs.
 
 - Dist jobs build a full release of the compiler for a specific platform,
-  including all the tools we ship through rustup; Those builds are then uploaded
+  including all the tools we ship through rustup. Those builds are then uploaded
   to the `rust-lang-ci2` S3 bucket and are available to be locally installed
   with the [rustup-toolchain-install-master] tool. The same builds are also used
   for actual releases: our release process basically consists of copying those
@@ -70,7 +70,7 @@ these execute the `x86_64-gnu-llvm-X`, `x86_64-gnu-tools`, `pr-check-1`, `pr-che
 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
+build to Windows mingw (without producing any artifacts), and they test the
 compiler using a *system* version of LLVM. Unfortunately, it would take too many
 resources to run the full test suite for each commit on every PR.
 
@@ -95,17 +95,16 @@ jobs that exercise various tests across operating systems and targets. The full
 test suite is quite slow; it can take several hours until all the `auto` CI
 jobs finish.
 
-Most platforms only run the build steps, some run a restricted set of tests,
+Most platforms only run the build steps, some run a restricted set of tests;
 only a subset run the full suite of tests (see Rust's [platform tiers]).
 
 Auto jobs are defined in the `auto` section of [`jobs.yml`]. They are executed
-on the `auto` branch under the `rust-lang/rust` repository and
-their results can be seen [here](https://github.com/rust-lang/rust/actions),
-although usually you will be notified of the result by a comment made by bors on
-the corresponding PR.
+on the `auto` branch under the `rust-lang/rust` repository,
+and the final result will be reported via a comment made by bors on the corresponding PR.
+The live results can be seen on [the GitHub Actions workflows page].
 
 At any given time, at most a single `auto` build is being executed. Find out
-more [here](#merging-prs-serially-with-bors).
+more in [Merging PRs serially with bors](#merging-prs-serially-with-bors).
 
 [platform tiers]: https://forge.rust-lang.org/release/platform-support.html#rust-platform-support
 
@@ -125,7 +124,7 @@ There are several use-cases for try builds:
   when you start a try build). To create a try build and schedule it for a
   performance benchmark, you can use the `@bors try @rust-timer queue` command
   combination.
-- Check the impact of the PR across the Rust ecosystem, using a [crater] run.
+- Check the impact of the PR across the Rust ecosystem, using a [Crater](crater.md) run.
   Again, a working compiler build is needed for this, which can be produced by
   the [dist-x86_64-linux] CI job.
 - Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it
@@ -134,11 +133,11 @@ There are several use-cases for try builds:
 By default, if you send a comment with `@bors try`, the jobs defined in the `try` section of
 [`jobs.yml`] will be executed. We call this mode a "fast try build". Such a try build
 will not execute any tests, and it will allow compilation warnings. It is useful when you want to
-get an optimized toolchain as fast as possible, for a crater run or performance benchmarks,
+get an optimized toolchain as fast as possible, for a Crater run or performance benchmarks,
 even if it might not be working fully correctly. If you want to do a full build for the default try job,
 specify its job name in a job pattern (explained below).
 
-If you want to run custom CI job(s) in a try build and make sure that they pass all tests and do
+If you want to run custom CI jobs in a try build and make sure that they pass all tests and do
 not produce any compilation warnings, you can select CI jobs to be executed by specifying a *job pattern*,
 which can be used in one of two ways:
 - You can add a set of `try-job: <job pattern>` directives to the PR description (described below) and then
@@ -151,8 +150,9 @@ which can be used in one of two ways:
 
 Each job pattern can either be an exact name of a job or a glob pattern that matches multiple jobs,
 for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using
-glob patterns, you might want to wrap them in backticks (`` ` ``) to avoid GitHub rendering
-the pattern as Markdown.
+glob patterns in the PR description, you can optionally wrap them in backticks (`` ` ``) to avoid GitHub rendering
+the pattern as Markdown if it contains e.g. an asterisk. Note that this escaping will not work when using
+the `@bors jobs=` parameter.
 
 The job pattern needs to match one or more jobs defined in the `auto` or `optional` sections
 of [`jobs.yml`]:
@@ -189,18 +189,17 @@ of [`jobs.yml`]:
 > that are exercised this way.
 
 Try builds are executed on the `try` branch under the `rust-lang/rust` repository and
-their results can be seen [here](https://github.com/rust-lang/rust/actions),
+their results can be seen on [the GitHub Actions workflows page],
 although usually you will be notified of the result by a comment made by bors on
 the corresponding PR.
 
 Multiple try builds can execute concurrently across different PRs, but there can be at most
 a single try build running on a single PR at any given time.
 
-Note that try builds are handled using the new [bors][new-bors] implementation.
+Note that try builds are handled using the [new bors] implementation.
 
 [rustc-perf]: https://github.com/rust-lang/rustc-perf
-[crater]: https://github.com/rust-lang/crater
-[new-bors]: https://github.com/rust-lang/bors
+[new bors]: https://github.com/rust-lang/bors
 
 ### Modifying CI jobs
 
@@ -210,8 +209,7 @@ If you want to modify what gets executed on our CI, you can simply modify the
 You can also modify what gets executed temporarily, for example to test a
 particular platform or configuration that is challenging to test locally (for
 example, if a Windows build fails, but you don't have access to a Windows
-machine). Don't hesitate to use CI resources in such situations to try out a
-fix!
+machine). Don't hesitate to use CI resources in such situations.
 
 You can perform an arbitrary CI job in two ways:
 - Use the [try build](#try-builds) functionality, and specify the CI jobs that
@@ -254,8 +252,8 @@ purposes.
 </div>
 
 Although you are welcome to use CI, just be conscious that this is a shared
-resource with limited concurrency. Try not to enable too many jobs at once (one
-or two should be sufficient in most cases).
+resource with limited concurrency. Try not to enable too many jobs at once;
+one or two should be sufficient in most cases.
 
 ## Merging PRs serially with bors
 
@@ -279,12 +277,12 @@ by listening for either Commit Statuses or Check Runs. Since the merge commit is
 based on the latest `master` and only one can be tested at the same time, when
 the results are green, `master` is fast-forwarded to that merge commit.
 
-Unfortunately testing a single PR at the time, combined with our long CI (~2
-hours for a full run), means we can’t merge too many PRs in a single day, and a
-single failure greatly impacts our throughput for the day. The maximum number of
+Unfortunately, testing a single PR at a time, combined with our long CI (~2
+hours for a full run), means we can’t merge a lot of PRs in a single day, and a
+single failure greatly impacts our throughput. The maximum number of
 PRs we can merge in a day is around ~10.
 
-The large CI run times and requirement for a large builder pool is largely due
+The long CI run times, and requirement for a large builder pool, is largely due
 to the fact that full release artifacts are built in the `dist-` builders. This
 is worth it because these release artifacts:
 
@@ -297,12 +295,11 @@ is worth it because these release artifacts:
 
 Some PRs don’t need the full test suite to be executed: trivial changes like
 typo fixes or README improvements *shouldn’t* break the build, and testing every
-single one of them for 2+ hours is a big waste of time. To solve this, we
+single one of them for 2+ hours would be wasteful. To solve this, we
 regularly create a "rollup", a PR where we merge several pending trivial PRs so
 they can be tested together. Rollups are created manually by a team member using
 the "create a rollup" button on the [merge queue]. The team member uses their
-judgment to decide if a PR is risky or not, and are the best tool we have at the
-moment to keep the queue in a manageable state.
+judgment to decide if a PR is risky or not.
 
 ## Docker
 
@@ -315,18 +312,22 @@ platform’s custom [Docker container]. This has a lot of advantages for us:
 - We can use ancient build environments to ensure maximum binary compatibility,
   for example [using older CentOS releases][dist-x86_64-linux] on our Linux
   builders.
-- We can avoid reinstalling tools (like QEMU or the Android emulator) every time
+- We can avoid reinstalling tools (like QEMU or the Android emulator) every time,
   thanks to Docker image caching.
-- Users can run the same tests in the same environment locally by just running
-  `cargo run --manifest-path src/ci/citool/Cargo.toml run-local <job-name>`, which is awesome to debug failures. Note that there are only linux docker images available locally due to licensing and
+- Users can run the same tests in the same environment locally by just running this command:
+
+      cargo run --manifest-path src/ci/citool/Cargo.toml run-local <job-name>
+
+  This is helpful for debugging failures.
+  Note that there are only Linux Docker images available locally due to licensing and
   other restrictions.
 
-The docker images prefixed with `dist-` are used for building artifacts while
+The Docker images prefixed with `dist-` are used for building artifacts while
 those without that prefix run tests and checks.
 
 We also run tests for less common architectures (mainly Tier 2 and Tier 3
-platforms) in CI. Since those platforms are not x86 we either run everything
-inside QEMU or just cross-compile if we don’t want to run the tests for that
+platforms) in CI. Since those platforms are not x86, we either run everything
+inside QEMU, or we just cross-compile if we don’t want to run the tests for that
 platform.
 
 These builders are running on a special pool of builders set up and maintained
@@ -363,41 +364,41 @@ invalidated if one of the following changes:
 [ghcr.io]: https://github.com/rust-lang/rust/pkgs/container/rust-ci
 [Docker registry caching]: https://docs.docker.com/build/cache/backends/registry/
 
-### LLVM caching with sccache
+### LLVM caching with Sccache
 
-We build some C/C++ stuff in various CI jobs, and we rely on [sccache] to cache
+We build some C/C++ stuff in various CI jobs, and we rely on [Sccache] to cache
 the intermediate LLVM artifacts. Sccache is a distributed ccache developed by
 Mozilla, which can use an object storage bucket as the storage backend.
 
-With sccache there's no need to calculate the hash key ourselves. Sccache
+With Sccache there's no need to calculate the hash key ourselves. Sccache
 invalidates the cache automatically when it detects changes to relevant inputs,
 such as the source code, the version of the compiler, and important environment
 variables.
-So we just pass the sccache wrapper on top of cargo and sccache does the rest.
+So we just pass the Sccache wrapper on top of Cargo and Sccache does the rest.
 
-We store the persistent artifacts on the S3 bucket `rust-lang-ci-sccache2`. So
-when the CI runs, if sccache sees that LLVM is being compiled with the same C/C++
-compiler and the LLVM source code is the same, sccache retrieves the individual
+We store the persistent artifacts on the S3 bucket, `rust-lang-ci-sccache2`. So
+when the CI runs, if Sccache sees that LLVM is being compiled with the same C/C++
+compiler and the LLVM source code is the same, Sccache retrieves the individual
 compiled translation units from S3.
 
 [sccache]: https://github.com/mozilla/sccache
 
 ## Custom tooling around CI
 
-During the years we developed some custom tooling to improve our CI experience.
+During the years, we developed some custom tooling to improve our CI experience.
 
 ### Rust Log Analyzer to show the error message in PRs
 
 The build logs for `rust-lang/rust` are huge, and it’s not practical to find
-what caused the build to fail by looking at the logs. To improve the developers’
-experience we developed a bot called [Rust Log Analyzer][rla] (RLA) that
-receives the build logs on failure and extracts the error message automatically,
-posting it on the PR.
+what caused the build to fail by looking at the logs.
+We therefore developed a bot called [Rust Log Analyzer][rla] (RLA) that
+receives the build logs on failure, and extracts the error message automatically,
+posting it on the PR thread.
 
 The bot is not hardcoded to look for error strings, but was trained with a bunch
 of build failures to recognize which lines are common between builds and which
 are not. While the generated snippets can be weird sometimes, the bot is pretty
-good at identifying the relevant lines even if it’s an error we've never seen
+good at identifying the relevant lines, even if it’s an error we've never seen
 before.
 
 [rla]: https://github.com/rust-lang/rust-log-analyzer
@@ -429,11 +430,11 @@ More information is available in the [toolstate documentation].
 
 ## Public CI dashboard
 
-To monitor the Rust CI, you can have a look at the [public dashboard] maintained by the infra-team.
+To monitor the Rust CI, you can have a look at the [public dashboard] maintained by the infra team.
 
 These are some useful panels from the dashboard:
 
-- Pipeline duration: check how long the auto builds takes to run.
+- Pipeline duration: check how long the auto builds take to run.
 - Top slowest jobs: check which jobs are taking the longest to run.
 - Change in median job duration: check what jobs are slowest than before. Useful
   to detect regressions.
@@ -456,8 +457,7 @@ this:
 2. Choose the job you are interested in on the left-hand side.
 3. Click on the gear icon and choose "View raw logs"
 4. Search for the string "Configure the build"
-5. All of the build settings are listed below that starting with the
-   `configure:` prefix.
+5. All of the build settings are listed on the line with the text, `build.configure-args`
 
 [GitHub Actions]: https://github.com/rust-lang/rust/actions
 [`jobs.yml`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/jobs.yml
@@ -467,3 +467,4 @@ this:
 [homu]: https://github.com/rust-lang/homu
 [merge queue]: https://bors.rust-lang.org/queue/rust
 [dist-x86_64-linux]: https://github.com/rust-lang/rust/blob/master/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+[the GitHub Actions workflows page]: https://github.com/rust-lang/rust/actions
diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
index 4caf4c0e0ee..74dbfb7d31b 100644
--- a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
+++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md
@@ -1,3 +1,56 @@
-# GCC codegen backend tests
+# GCC codegen backend
 
-TODO: please add some more information to this page.
+If you ran into an error related to tests executed with the GCC codegen backend on CI,
+you can use the following command to run tests locally using the GCC backend:
+
+```bash
+./x test tests/ui --set 'rust.codegen-backends = ["llvm", "gcc"]' --test-codegen-backend gcc
+```
+
+Below, you can find more information about how to configure the GCC backend in bootstrap.
+
+## Choosing which codegen backends are built
+
+The `rust.codegen-backends = [...]` bootstrap option affects which codegen backends will be built and
+included in the sysroot of the produced `rustc`. To use the GCC codegen backend, `"gcc"` has to
+be included in this array in `bootstrap.toml`:
+
+```toml
+rust.codegen-backends = ["llvm", "gcc"]
+```
+
+If you don't want to change your `bootstrap.toml` file, you can alternatively run your `x`
+commands with `--set rust.codegen-backends=["llvm", "gcc"]'`. For example:
+
+```bash
+./x build --set 'rust.codegen-backends=["llvm", "gcc"]'
+```
+
+The first backend in the `codegen-backends` array will determine which backend will be used as the
+*default backend* of the built `rustc`. This also determines which backend will be used to compile the
+stage 1 standard library (or anything built in stage 2+). To produce `rustc` that uses the GCC backend
+by default, you can thus put `"gcc"` as the first element of this array:
+
+```bash
+./x build --set 'rust.codegen-backends=["gcc"]' library
+```
+
+## Choosing the codegen backend used in tests
+
+To run compiler tests with the GCC codegen backend being used to build the test Rust programs, you can use the
+`--test-codegen-backend` flag:
+
+```bash
+./x test tests/ui --test-codegen-backend gcc
+```
+
+Note that in order for this to work, the tested compiler must have the GCC codegen backend available in its sysroot
+directory. You can achieve that using the [instructions above](#choosing-which-codegen-backends-are-built).
+
+## Downloading GCC from CI
+
+The `gcc.download-ci-gcc` bootstrap option controls if GCC (which is a dependency of the GCC codegen backend)
+will be downloaded from CI or built locally. The default value is `true`, which will download GCC from CI
+if there are no local changes to the GCC sources and the given host target is available on CI.
+
+Note that GCC can currently only be downloaded from CI for the `x86_64-unknown-linux-gnu` target.
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index a4a729935fa..0234b394c2a 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -72,7 +72,7 @@ The following test suites are available, with links for more information:
 | [`mir-opt`](#mir-opt-tests)               | Check MIR generation and optimizations                                                                              |
 | [`coverage`](#coverage-tests)             | Check coverage instrumentation                                                                                      |
 | [`coverage-run-rustdoc`](#coverage-tests) | `coverage` tests that also run instrumented doctests                                                                |
-| [`crashes`](#crashes-tests)               | Check that the compiler ICEs/panics/crashes on certain inputs to catch accidental fixes                             |
+| [`crashes`](#crash-tests)               | Check that the compiler ICEs/panics/crashes on certain inputs to catch accidental fixes                             |
 
 ### General purpose test suite
 
@@ -557,7 +557,7 @@ only running the main `coverage` suite.
 [`src/tools/coverage-dump`]: https://github.com/rust-lang/rust/tree/master/src/tools/coverage-dump
 [`tests/coverage-run-rustdoc`]: https://github.com/rust-lang/rust/tree/master/tests/coverage-run-rustdoc
 
-### Crashes tests
+### Crash tests
 
 [`tests/crashes`] serve as a collection of tests that are expected to cause the
 compiler to ICE, panic or crash in some other way, so that accidental fixes are
@@ -580,13 +580,13 @@ recommended to include test cases from several issues in a single PR.
 When you do so, each issue number should be noted in the file name (`12345.rs`
 should suffice) and also inside the file by means of a `//@ known-bug: #12345`
 directive. Please [label][labeling] the relevant issues with `S-bug-has-test`
-afterwards.
+once your PR is merged.
 
 If you happen to fix one of the crashes, please move it to a fitting
 subdirectory in `tests/ui` and give it a meaningful name. Please add a doc
 comment at the top of the file explaining why this test exists, even better if
 you can briefly explain how the example causes rustc to crash previously and
-what was done to prevent rustc to ICE/panic/crash.
+what was done to prevent rustc to ICE / panic / crash.
 
 Adding
 
diff --git a/src/doc/rustc-dev-guide/src/tests/crater.md b/src/doc/rustc-dev-guide/src/tests/crater.md
index 9d4ac87daf3..96bb5a4f2ae 100644
--- a/src/doc/rustc-dev-guide/src/tests/crater.md
+++ b/src/doc/rustc-dev-guide/src/tests/crater.md
@@ -8,30 +8,30 @@ stable compiler versions.
 
 ## When to run Crater
 
-You should request a crater run if your PR makes large changes to the compiler
+You should request a Crater run if your PR makes large changes to the compiler
 or could cause breakage. If you are unsure, feel free to ask your PR's reviewer.
 
 ## Requesting Crater Runs
 
-The rust team maintains a few machines that can be used for running crater runs
-on the changes introduced by a PR. If your PR needs a crater run, leave a
+The Rust team maintains a few machines that can be used for Crater runs
+on the changes introduced by a PR. If your PR needs a Crater run, leave a
 comment for the triage team in the PR thread. Please inform the team whether you
-require a "check-only" crater run, a "build only" crater run, or a
-"build-and-test" crater run. The difference is primarily in time; the
-conservative (if you're not sure) option is to go for the build-and-test run. If
+require a "check-only" Crater run, a "build only" Crater run, or a
+"build-and-test" Crater run. The difference is primarily in time;
+if you're not sure, go for the build-and-test run. If
 making changes that will only have an effect at compile-time (e.g., implementing
-a new trait) then you only need a check run.
+a new trait), then you only need a check run.
 
 Your PR will be enqueued by the triage team and the results will be posted when
-they are ready. Check runs will take around ~3-4 days, with the other two taking
+they are ready. Check runs will take around ~3-4 days, and the other two taking
 5-6 days on average.
 
-While crater is really useful, it is also important to be aware of a few
+While Crater is really useful, it is also important to be aware of a few
 caveats:
 
 - Not all code is on crates.io! There is a lot of code in repos on GitHub and
   elsewhere. Also, companies may not wish to publish their code. Thus, a
-  successful crater run is not a magically green light that there will be no
+  successful Crater run does not mean there will be no
   breakage; you still need to be careful.
 
 - Crater only runs Linux builds on x86_64. Thus, other architectures and
@@ -41,5 +41,5 @@ caveats:
   the crate doesn't compile any more (e.g. used old nightly features), has
   broken or flaky tests, requires network access, or other reasons.
 
-- Before crater can be run, `@bors try` needs to succeed in building artifacts.
-  This means that if your code doesn't compile, you cannot run crater.
+- Before Crater can be run, `@bors try` needs to succeed in building artifacts.
+  This means that if your code doesn't compile, you cannot run Crater.
diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md
index 5e5b81fc65b..a7cdab73e79 100644
--- a/src/doc/rustc-dev-guide/src/tracing.md
+++ b/src/doc/rustc-dev-guide/src/tracing.md
@@ -109,7 +109,7 @@ Miri, use `MIRI_LOG` instead. You get the idea :)
 
 See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to
 see the full syntax you can use. (Note: unlike the compiler, the [`tracing`]
-crate and its examples use the `RUST_LOG` environment variable. rustc, rustdoc,
+crate and its examples use the `RUSTC_LOG` environment variable. rustc, rustdoc,
 and other tools set custom environment variables.)
 
 **Note that unless you use a very strict filter, the logger will emit a lot of
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index e4bf33dd8a0..619eebd15bd 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -52,7 +52,6 @@
     - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
     - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md)
     - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md)
-    - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
     - [arm-none-eabi](platform-support/arm-none-eabi.md)
       - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
       - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
@@ -65,12 +64,14 @@
       - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md)
       - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md)
       - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md)
-    - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
+    - [arm\*-unknown-linux-\*](./platform-support/arm-linux.md)
+        - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
+        - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
+        - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
+        - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
     - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md)
     - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
-    - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
-    - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [armv7a-vex-v5](platform-support/armv7a-vex-v5.md)
     - [\*-android and \*-androideabi](platform-support/android.md)
     - [\*-linux-ohos](platform-support/openharmony.md)
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 445b10188e3..0e340de4daa 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -471,11 +471,13 @@ If not specified, overflow checks are enabled if
 This option lets you control what happens when the code panics.
 
 * `abort`: terminate the process upon panic
+* `immediate-abort`: terminate the process upon panic, and do not call any panic hooks
 * `unwind`: unwind the stack upon panic
 
 If not specified, the default depends on the target.
 
 If any crate in the crate graph uses `abort`, the final binary (`bin`, `dylib`, `cdylib`, `staticlib`) must also use `abort`.
+If any crate in the crate graph uses `immediate-abort`, every crate in the graph must use `immediate-abort`.
 If `std` is used as a `dylib` with `unwind`, the final binary must also use `unwind`.
 
 ## passes
diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md
index ab95aa2e5a1..32e712a48d7 100644
--- a/src/doc/rustc/src/linker-plugin-lto.md
+++ b/src/doc/rustc/src/linker-plugin-lto.md
@@ -144,7 +144,7 @@ def minor_version(version):
 INSTALL_TOOLCHAIN = ["rustup", "toolchain", "install", "--profile", "minimal"]
 subprocess.run(INSTALL_TOOLCHAIN + ["nightly"])
 
-LOWER_BOUND = 73
+LOWER_BOUND = 87
 NIGHTLY_VERSION = minor_version(subprocess.run(
     ["rustc", "+nightly", "--version"],
     capture_output=True,
@@ -201,6 +201,9 @@ The following table shows known good combinations of toolchain versions.
 | 1.65 - 1.69  |      15       |
 | 1.70 - 1.72  |      16       |
 | 1.73 - 1.77  |      17       |
-| 1.78         |      18       |
+| 1.78 - 1.81  |      18       |
+| 1.82 - 1.86  |      19       |
+| 1.87 - 1.90  |      20       |
+| 1.91 - 1.92  |      21       |
 
 Note that the compatibility policy for this feature might change in the future.
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index e5e46f72637..c0882a7a45e 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -156,8 +156,6 @@ target | std | notes
 `arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
 `arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
-[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
-[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
 [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
@@ -283,6 +281,8 @@ target | std | host | notes
 [`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
 [`arm64e-apple-tvos`](platform-support/arm64e-apple-tvos.md)  | ✓ | | ARM64e Apple tvOS
 [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | Arm BE8 the default Arm big-endian architecture since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
+[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
+[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
 [`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Bare Armv4T
 `armv4t-unknown-linux-gnueabi` | ? |  | Armv4T Linux
 [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Bare Armv5TE
@@ -431,6 +431,7 @@ target | std | host | notes
 `x86_64-unknown-l4re-uclibc` | ? |  |
 [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
 [`x86_64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? |   | x86_64 Managarm
+[`x86_64-unknown-motor`[(platform-support/motor.md) | ? |  | x86_64 Motor OS
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 [`x86_64-unknown-trusty`](platform-support/trusty.md) | ✓ |  |
 `x86_64-uwp-windows-gnu` | ✓ |  |
diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md
new file mode 100644
index 00000000000..5f40743f3d0
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/arm-linux.md
@@ -0,0 +1,217 @@
+# Arm Linux support in Rust
+
+The Arm Architecture has been around since the mid-1980s, going through nine
+major revisions, many minor revisions, and spanning both 32-bith and 64-bit
+architectures. This page covers 32-bit Arm platforms that run some form of
+Linux (but not Android). Those targets are:
+
+* `arm-unknown-linux-gnueabi`
+* `arm-unknown-linux-gnueabihf`
+* `arm-unknown-linux-musleabi`
+* `arm-unknown-linux-musleabihf`
+* [`armeb-unknown-linux-gnueabi`](armeb-unknown-linux-gnueabi.md)
+* `armv4t-unknown-linux-gnueabi`
+* [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md)
+* `armv5te-unknown-linux-musleabi`
+* `armv5te-unknown-linux-uclibceabi`
+* `armv7-unknown-linux-gnueabi`
+* `armv7-unknown-linux-gnueabihf`
+* `armv7-unknown-linux-musleabi`
+* `armv7-unknown-linux-musleabihf`
+* `armv7-unknown-linux-ohos`
+* [`armv7-unknown-linux-uclibceabi`](armv7-unknown-linux-uclibceabi.md)
+* [`armv7-unknown-linux-uclibceabihf`](armv7-unknown-linux-uclibceabihf.md)
+* `thumbv7neon-unknown-linux-gnueabihf`
+* `thumbv7neon-unknown-linux-musleabihf`
+
+Some of these targets have dedicated pages and some do not. This is largely
+due to historical accident, or the enthusiasm of the maintainers. This
+document attempts to cover all the targets, but only in broad terms.
+
+To make sense of this list, the architecture and ABI component of the
+`<architecture>-unknown-linux-<abi>` tuple will be discussed separately.
+
+The second part of the tuple is `unknown` because these systems don't come
+from any one specific vendor (like `powerpc-ibm-aix` or
+`aarch64-apple-darwin`). The third part is `linux`, because this page only
+discusses Linux targets.
+
+## Architecture Component
+
+* `arm`
+* `armeb`
+* `armv4t`
+* `armv5te`
+* `armv7`
+* `thumbv7neon`
+
+The architecture component simply called `arm` corresponds to the Armv6
+architecture - that is, version 6 of the Arm Architecture as defined in
+version 6 of the Arm Architecture Reference Manual (the Arm ARM). This was the
+last 'legacy' release of the Arm architecture, before they split into
+Application, Real-Time and Microcontroller profiles (leading to Armv7-A,
+Armv7-R and Armv7-M). Processors that implement the Armv6 architecture include
+the ARM1176JZF-S, as found in BCM2835 SoC that powers the Raspberry Pi Zero.
+Arm processors are generally fairly backwards compatible, especially for
+user-mode code, so code compiled for the `arm` architecture should also work
+on newer ARMv7-A systems, or even 64/32-bit Armv8-A systems.
+
+The `armeb` architecture component specifies an Armv6 processor running in Big
+Endian mode (`eb` is for big-endian - the letters are backwards because
+engineers used to little-endian systems perceive big-endian numbers to be
+written into memory backwards, and they thought it was funnier like that).
+Most Arm processors can operate in either little-endian or big-endian mode and
+little-endian mode is by far the most common. However, if for whatever reason
+you wish to store your Most Significant Bytes first, these targets are
+available. They just aren't terribly well tested, or compatible with most
+existing pre-compiled Arm libraries.
+
+Targets that start with `armv4t` are for processors implementing the Armv4T
+architecture from 1994. These include the ARM7TDMI, as found in the Nokia 6110
+brick-phone and the Game Boy Advance. The 'T' stands for *Thumb* and indicate
+that the processors can execute smaller 16-bit versions of some of the 32-bit
+Arm instructions. Because a Thumb is like a small version of an Arm.
+
+Targets that start with `armv5te` are for processors implementing the Armv5TE
+architecture. These are mostly from the ARM9 family, like the ARM946E-S found
+in the Nintendo DS. If you are programming an Arm machine from the early
+2000s, this might be what you need.
+
+The `armv7` is arguably a misnomer, and it should be `armv7a`. This is because
+it corresponds to the Application profile of Armv7 (i.e. Armv7-A), as opposed
+to the Real-Time or Microcontroller profile. Processors implementing this
+architecture include the Cortex-A7 and Cortex-A8.
+
+The `thumbv7neon` component indicates support for a processor that implements
+ARMv7-A (the same as `armv7`), it generates Thumb instructions (technically
+Thumb-2, also known as the T32 ISA) as opposed to Arm instructions (also known
+as the A32 ISA). These instructions are smaller, giving more code per KB of
+RAM, but may have a performance penalty if they take two instructions to do
+something Arm instructions could do in one. It's a complex trade-off and you
+should be doing benchmarks to work out which is better for you, if you
+strongly care about code size and/or performance. This component also enables
+support for Arm's SIMD extensions, known as Neon. These extensions will
+improve performance for certain kinds of repetitive operations.
+
+## ABI Component
+
+* `gnueabi`
+* `gnueabihf`
+* `musleabi`
+* `musleabihf`
+* `ohos`
+* `uclibceabi`
+* `uclibceabihf`
+
+You will need to select the appropriate ABI to match the system you want to be
+running this code on. For example, running `eabihf` code on an `eabi` system
+will not work correctly.
+
+The `gnueabi` ABI component indicates support for using the GNU C Library
+(glibc), and the Arm Embedded ABI (EABI). The EABI is a replacement for the
+original ABI (now called the Old ABI or OABI), and it is the standard ABI for
+32-bit Arm systems. With this ABI, function parameters that are `f32` or `f64`
+are passed as if they were integers, instead of being passed via in FPU
+registers. Generally these targets also disable the use of the FPU entirely,
+although that isn't always true.
+
+The `gnueabihf` ABI component is like `gnueabi`, except that it support the
+'hard-float' of the EABI. That is, function parameters that are `f32` or `f64`
+are passed in FPU registers. Naturally, this makes the FPU mandatory.
+
+Most 'desktop' Linux distributions (Debian, Ubuntu, Fedora, etc) use the GNU C
+Library and so you should probably select either `gnueabi` or `gnueabihf`,
+depending on whether your distribution is using 'soft-float' (EABI) or
+'hard-float' (EABIHF). Debian happens to offer
+[both](https://wiki.debian.org/ArmEabiPort)
+[kinds](https://wiki.debian.org/ArmHardFloatPort).
+
+The `musleabi` and `musleabihf` ABI components offer support for the [musl C
+library](https://musl.libc.org/). This C library can be used to create 'static
+binaries' that have no run-time library requirements (a feature that glibc
+does not support). There are soft-float (`eabi`) and hard-float (`eabihf`)
+variants, as per the `gnu*` targets above.
+
+The `uclibceabi` and `uclibceabihf` ABI components are for the [uClibc-ng C
+library](https://uclibc-ng.org/). This is sometimes used in light-weight
+embedded Linux distributions, like those created with
+[buildroot](https://www.buildroot.org/).
+
+## Cross Compilation
+
+Unfortunately, 32-bit Arm machines are generally not the fastest around, and
+they don't have much RAM. This means you are likely to be cross-compiling.
+
+To do this, you need to give Rust a suitable linker to use - one that knows
+the Arm architecture, and more importantly, knows where to find a suitable C
+Library to link against.
+
+To do that, you can add the `linker` property to your `.cargo/config.toml`.
+Typically you would refer to a suitable copy of GCC that has built as a
+cross-compiler, alongside a C library.
+
+```toml
+[target.arm-unknown-linux-gnueabi]
+linker = "arm-linux-gnueabi-gcc"
+```
+
+On Debian Linux, you could install such a cross-compilation toolchain with
+`apt install gcc-arm-linux-gnueabi`. For more exotic combinations, you might
+need to build a bespoke version of GCC using [crosstool-ng].
+
+[crosstool-ng]: https://github.com/crosstool-ng/crosstool-ng
+
+Note that for GCC, all 32-bit Arm architectures are handled in the same build
+- there are no separate Armv4T or Armv6 builds of GCC. The architecture is
+selected with flags, like `-march=armv6`, but they aren't required for the
+linker.
+
+Let's assume we are on some Debian machine, and we want to build a basic Arm
+Linux binary for a distribution using the GNU C Library, targeting Armv6 with
+a hard-float ABI. Such a binary should work on a Raspberry Pi, for example.
+The commands are:
+
+```bash
+sudo apt install -y gcc-arm-linux-gnueabihf
+rustup target add arm-unknown-linux-gnueabihf
+cargo new --bin armdemo
+cd armdemo
+mkdir .cargo
+cat > .cargo/config.toml << EOF
+[target.arm-unknown-linux-gnueabihf]
+linker = "arm-linux-gnueabihf-gcc"
+EOF
+cargo build --target=arm-unknown-linux-gnueabihf
+```
+
+This will give us our ARM Linux binary for the GNU C Library with a soft-float ABI:
+
+```console
+$ file ./target/arm-unknown-linux-gnueabi/debug/armdemo
+./target/arm-unknown-linux-gnueabi/debug/armdemo: ELF 32-bit LSB pie
+  executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter
+  /lib/ld-linux.so.3, BuildID[sha1]=dd0b9aa5ae876330fd4e2fcf393850f083ec7fcd,
+  for GNU/Linux 3.2.0, with debug_info, not stripped
+```
+
+If you are building C code as part of your Rust project, you may want to
+direct `cc-rs` to use an appropriate cross-compiler with the `CROSS_COMPILE`
+environment variable. You may also want to set the CFLAGS environment variable
+for the target. For example:
+
+```bash
+export CROSS_COMPILE=arm-linux-gnueabi
+export CFLAGS_arm_unknown_linux_gnueabi="-march=armv6"
+```
+
+(Note that the dashes (`-`) turn to underscores (`_`) to form the name of the
+CFLAGS environment variable)
+
+If you are building for a Tier 3 target using `-Zbuild-std` (on Nightly Rust),
+you need to set these variables as well:
+
+```bash
+export CXX_arm_unknown_linux_gnueabi=arm-linux-gnueabi-g++
+export CC_arm_unknown_linux_gnueabi=arm-linux-gnueabi-gcc
+cargo +nightly build -Zbuild-std --target=arm-unknown-linux-gnueabi
+```
diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
index 7c1c5db7076..cd0623f73a1 100644
--- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
+++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
@@ -3,6 +3,9 @@
 
 Target for cross-compiling Linux user-mode applications targeting the Arm BE8 architecture.
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Overview
 BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian Arm systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats).
 
diff --git a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
index 3e90319c373..d5c676ea9a4 100644
--- a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md
@@ -1,6 +1,6 @@
 # `armebv7r-none-eabi` and `armebv7r-none-eabihf`
 
-* **Tier: 2**
+* **Tier: 3**
 * **Library Support:** core and alloc (bare-metal, `#![no_std]`)
 
 Bare-metal target for CPUs in the Armv7-R architecture family running in Big
diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
index 0aebbc34d40..a924f476411 100644
--- a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
+++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md
@@ -5,6 +5,9 @@
 This target supports Linux programs with glibc on ARMv5TE CPUs without
 floating-point units.
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Target maintainers
 
 There are currently no formally documented target maintainers.
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
index e553c49589d..4ab0a07090a 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
@@ -4,6 +4,9 @@
 
 This target supports Armv7-A softfloat CPUs and uses the uclibc-ng standard library. This is a common configuration on many consumer routers (e.g., Netgear R7000, Asus RT-AC68U).
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Target maintainers
 
 [@lancethepants](https://github.com/lancethepants)
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
index 91f3ea886cc..9fb24906b4f 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
@@ -4,6 +4,9 @@
 
 This tier supports the Armv7-A processor running a Linux kernel and uClibc-ng standard library.  It provides full support for rust and the rust standard library.
 
+See [`arm-linux`](arm-linux.md) for information applicable to all Arm Linux
+targets.
+
 ## Target Maintainers
 
 [@skrap](https://github.com/skrap)
diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md
index a7da1b16f7e..3677f8931dd 100644
--- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md
+++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md
@@ -4,7 +4,7 @@
 
 Allows compiling user programs for the [VEX V5 Brain](https://www.vexrobotics.com/276-4810.html), a microcontroller for educational and competitive robotics.
 
-Rust support for this target is not affiliated with VEX Robotics or IFI.
+Rust support for this target is not affiliated with VEX Robotics or IFI, and does not link to any official VEX SDK.
 
 ## Target maintainers
 
@@ -17,11 +17,24 @@ This target is maintained by members of the [vexide](https://github.com/vexide)
 
 ## Requirements
 
-This target is cross-compiled and currently requires `#![no_std]`. Dynamic linking is unsupported.
+This target is cross-compiled. Dynamic linking is unsupported.
 
-When compiling for this target, the "C" calling convention maps to AAPCS with VFP registers (hard float ABI) and the "system" calling convention maps to AAPCS without VFP registers (soft float ABI).
+`#![no_std]` crates can be built using `build-std` to build `core` and `panic_abort` and optionally `alloc`. Unwinding panics are not yet supported on this target.
 
-This target generates binaries in the ELF format that may uploaded to the brain with external tools.
+`std` has only partial support due platform limitations. Notably:
+- `std::process` and `std::net` are unimplemented. `std::thread` only supports sleeping and yielding, as this is a single-threaded environment.
+- `std::time` has full support for `Instant`, but no support for `SystemTime`.
+- `std::io` has full support for `stdin`/`stdout`/`stderr`. `stdout` and `stderr` both write to to USB channel 1 on this platform and are not differentiated.
+- `std::fs` has limited support for reading or writing to files. Directory operations, file deletion, and some file opening features are unsupported and will return errors.
+- A global allocator implemented on top of `dlmalloc` is provided.
+- Modules that do not need to interact with the OS beyond allocation such as `std::collections`, `std::hash`, `std::future`, `std::sync`, etc are fully supported.
+- Random number generation and hashing is insecure, as there is no reliable source of entropy on this platform.
+
+In order to support some APIs, users are expected to provide a supporting runtime SDK for `libstd` to link against. This library may be provided either by [`vex-sdk-build`](https://github.com/vexide/vex-sdk/tree/main/packages/vex-sdk-build) (which will download an official SDK from VEX) or through an open-source implementation such as [`vex-sdk-jumptable`](https://crates.io/crates/vex-sdk-jumptable).
+
+When compiling for this target, the "C" calling convention maps to AAPCS with VFP registers (hard float ABI) and the "system" calling convention maps to AAPCS without VFP registers (softfp ABI).
+
+This target generates binaries in the ELF format that may be uploaded to the brain with external tools.
 
 ## Building the target
 
@@ -29,10 +42,7 @@ You can build Rust with support for this target by adding it to the `target` lis
 
 ## Building Rust programs
 
-Rust does not yet ship pre-compiled artifacts for this target. To compile for
-this target, you will either need to build Rust with the target enabled (see
-"Building the target" above), or build your own copy of `core` by using
-`build-std` or similar.
+Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `core` by using `build-std` or similar.
 
 When the compiler builds a binary, an ELF build artifact will be produced. Additional tools are required for this artifact to be recognizable to VEXos as a user program.
 
diff --git a/src/doc/rustc/src/platform-support/motor.md b/src/doc/rustc/src/platform-support/motor.md
new file mode 100644
index 00000000000..e7aa7b23f3a
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/motor.md
@@ -0,0 +1,45 @@
+# `x86_64-unknown-motor`
+
+**Tier: 3**
+
+[Motor OS](https://github.com/moturus/motor-os) is a new operating system
+for virtualized environments.
+
+## Target maintainers
+
+[@lasiotus](https://github.com/lasiotus)
+
+## Requirements
+
+This target is cross-compiled. There are no special requirements for the host.
+
+Motor OS uses the ELF file format.
+
+## Building the target
+
+The target can be built by enabling it for a `rustc` build, for example:
+
+```toml
+[build]
+build-stage = 2
+target = ["x86_64-unknown-motor"]
+```
+
+## Building Rust programs
+
+Rust standard library is fully supported/implemented, but is not yet part of
+the official Rust repo, so an out-of-tree building process should be
+followed, as described in the
+[build doc](https://github.com/moturus/motor-os/blob/main/docs/build.md).
+
+## Testing
+
+Cross-compiled Rust binaries and test artifacts can be executed in Motor OS VMs,
+as described in e.g.
+[Hello Motor OS](https://github.com/moturus/motor-os/blob/main/docs/recipes/hello-motor-os.md)
+example.
+
+## Cross-compilation toolchains and C code
+
+C code can be compiled as part of Rust cargo projects. However, there is
+no libc support.
diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md
index 109942518fc..2bcc453a532 100644
--- a/src/doc/rustc/src/symbol-mangling/v0.md
+++ b/src/doc/rustc/src/symbol-mangling/v0.md
@@ -710,6 +710,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
 [mut-ptr-type]: #mut-ptr-type
 [fn-type]: #fn-type
 [dyn-trait-type]: #dyn-trait-type
+[pattern-type]: #pattern-type
 
 > type → \
 > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[basic-type]* \
@@ -722,6 +723,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
 > &nbsp;&nbsp; | *[mut-ptr-type]* \
 > &nbsp;&nbsp; | *[fn-type]* \
 > &nbsp;&nbsp; | *[dyn-trait-type]* \
+> &nbsp;&nbsp; | *[pattern-type]* \
 > &nbsp;&nbsp; | *[path]* \
 > &nbsp;&nbsp; | *[backref]*
 
@@ -830,6 +832,23 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`.
 [fn-sig]: #fn-sig
 [abi]: #abi
 
+* `W` — A [pattern-type][pattern-tpye] `u32 is 0..100`.
+  > <span id="pattern-type">pattern-type</span> → `W` *[pattern-kind]*
+  >
+  > <span id="pattern-kind">pattern-kind</span> → \
+  > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
+  > &nbsp;&nbsp; *[or-pattern-kind]*
+  >
+  > <span id="range-pattern-kind">range-pattern-kind</span> → `R` *[const]* *[const]*
+  >
+  > <span id="or-pattern-kind">or-pattern-kind</span> → `O` *[pattern-kind]* `E`
+
+  While or patterns can be nested in theory, in practice this does not happen and they are instead flattened.
+
+  Range patterns have a start and end constant that are both included in the range.
+  The end must be larger than the start (there can be no wraparound). To emulate wraparound,
+  you need to use an or pattern of the two ranges to the upper limit and from the lower limit.
+
 * `D` — A [trait object][reference-trait-object] `dyn Trait<Assoc=X> + Send + 'a`.
 
   > <span id="dyn-trait-type">dyn-trait-type</span> → `D` *[dyn-bounds]* *[lifetime]*
@@ -1139,6 +1158,7 @@ The following is a summary of all of the productions of the symbol grammar.
 > &nbsp;&nbsp; | *[mut-ptr-type]* \
 > &nbsp;&nbsp; | *[fn-type]* \
 > &nbsp;&nbsp; | *[dyn-trait-type]* \
+> &nbsp;&nbsp; | *[pattern-type]* \
 > &nbsp;&nbsp; | *[path]* \
 > &nbsp;&nbsp; | *[backref]*
 >
@@ -1152,6 +1172,14 @@ The following is a summary of all of the productions of the symbol grammar.
 > [mut-ptr-type] → `O` *[type]* \
 > [fn-type] → `F` *[fn-sig]* \
 > [dyn-trait-type] → `D` *[dyn-bounds]* *[lifetime]*
+> [pattern-type] → `W` *[pattern-kind]*
+>
+> [pattern-kind] → \
+> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
+> &nbsp;&nbsp; *[or-pattern-kind]*
+>
+> [range-pattern-kind] -> `R` *[const]* *[const]* \
+> [or-pattern-kind] -> `O` *[pattern-kind]* `E` \
 >
 > [namespace] → *[lower]* | *[upper]*
 >
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index c02c9aebe7e..f49edb2ac78 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -89,20 +89,30 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
 This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
 to automatically go to the first result.
 
-## `#[repr(transparent)]`: Documenting the transparent representation
+## `#[repr(...)]`: Documenting the representation of a type
+
+Generally, rustdoc only displays the representation of a given type if none of its variants are
+`#[doc(hidden)]` and if all of its fields are public and not `#[doc(hidden)]` since it's likely
+not meant to be considered part of the public ABI otherwise.
+
+Note that there's no way to overwrite that heuristic and force rustdoc to show the representation
+regardless.
+
+### `#[repr(transparent)]`
 
 You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and
 in the [Rustonomicon][repr-trans-nomicon].
 
 Since this representation is only considered part of the public ABI if the single field with non-trivial
-size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays
-the attribute if and only if the non-1-ZST field is public or at least one field is public in case all
-fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized.
+size or alignment is public and if the documentation does not state otherwise, rustdoc helpfully displays
+the attribute if and only if the non-1-ZST field is public and not `#[doc(hidden)]` or
+– in case all fields are 1-ZST fields — at least one field is public and not `#[doc(hidden)]`.
+The term *1-ZST* refers to types that are one-aligned and zero-sized.
 
 It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]`
 if one wishes to declare the representation as private even if the non-1-ZST field is public.
 However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work.
-Therefore, if you would like to do so, you should always write it down in prose independently of whether
+Therefore, if you would like to do so, you should always write that down in prose independently of whether
 you use `cfg_attr` or not.
 
 [repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 25c929a1dba..4327a80cd08 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -739,7 +739,7 @@ This flag can be passed multiple times to nest wrappers.
 
 ## Passing arguments to rustc when compiling doctests
 
-You can use the `--doctest-compilation-args` flag if you want to add options when compiling the
+You can use the `--doctest-build-arg` flag if you want to add options when compiling the
 doctest. For example if you have:
 
 ```rust,no_run
@@ -784,10 +784,10 @@ failures:
 test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s
 ```
 
-But if you can limit the lint level to warning by using `--doctest_compilation_args=--cap-lints=warn`:
+But if you can limit the lint level to warning by using `--doctest-build-arg=--cap-lints=warn`:
 
 ```console
-$ rustdoc --test --doctest_compilation_args=--cap-lints=warn file.rs
+$ rustdoc --test --doctest-build-arg=--cap-lints=warn file.rs
 
 running 1 test
 test tests/rustdoc-ui/doctest/rustflags.rs - Bar (line 5) ... ok
@@ -795,24 +795,8 @@ test tests/rustdoc-ui/doctest/rustflags.rs - Bar (line 5) ... ok
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s
 ```
 
-The parsing of arguments works as follows: if it encounters a `"` or a `'`, it will continue
-until it finds the character unescaped (without a prepending `\`). If not inside a string, a
-whitespace character will also split arguments. Example:
-
-```text
-"hello 'a'\" ok" how are   'you today?'
-```
-
-will be split as follows:
-
-```text
-[
-    "hello 'a'\" ok",
-    "how",
-    "are",
-    "you today?",
-]
-```
+In order to pass multiple arguments to the underlying compiler,
+pass `--doctest-build-arg ARG` for each argument `ARG`.
 
 ## `--generate-macro-expansion`: Generate macros expansion toggles in source code
 
diff --git a/src/doc/unstable-book/src/compiler-flags/branch-protection.md b/src/doc/unstable-book/src/compiler-flags/branch-protection.md
index f0cc44a07f3..c15567dcac2 100644
--- a/src/doc/unstable-book/src/compiler-flags/branch-protection.md
+++ b/src/doc/unstable-book/src/compiler-flags/branch-protection.md
@@ -13,6 +13,7 @@ It takes some combination of the following values, separated by a `,`.
 - `leaf` - Enable pointer authentication for all functions, including leaf functions.
 - `b-key` - Sign return addresses with key B, instead of the default key A.
 - `bti` - Enable branch target identification.
+- `gcs` - Enable guarded control stack support.
 
 `leaf`, `b-key` and `pc` are only valid if `pac-ret` was previously specified.
 For example, `-Z branch-protection=bti,pac-ret,leaf` is valid, but
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index d9566c9f55c..9434868dc08 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -36,6 +36,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | PowerPC      | `freg`         | `f[0-31]`                          | `f`                  |
 | PowerPC      | `vreg`         | `v[0-31]`                          | `v`                  |
 | PowerPC      | `cr`           | `cr[0-7]`, `cr`                    | Only clobbers        |
+| PowerPC      | `ctr`          | `ctr`                              | Only clobbers        |
+| PowerPC      | `lr`           | `lr`                               | Only clobbers        |
 | PowerPC      | `xer`          | `xer`                              | Only clobbers        |
 | wasm32       | `local`        | None\*                             | `r`                  |
 | BPF          | `reg`          | `r[0-10]`                          | `r`                  |
@@ -78,6 +80,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | PowerPC      | `vreg`                          | `altivec`      | `i8x16`, `i16x8`, `i32x4`, `f32x4`      |
 | PowerPC      | `vreg`                          | `vsx`          | `f32`, `f64`, `i64x2`, `f64x2`          |
 | PowerPC      | `cr`                            | N/A            | Only clobbers                           |
+| PowerPC      | `ctr`                           | N/A            | Only clobbers                           |
+| PowerPC      | `lr`                            | N/A            | Only clobbers                           |
 | PowerPC      | `xer`                           | N/A            | Only clobbers                           |
 | wasm32       | `local`                         | None           | `i8` `i16` `i32` `i64` `f32` `f64`      |
 | BPF          | `reg`                           | None           | `i8` `i16` `i32` `i64`                  |
@@ -150,8 +154,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | MIPS         | `$ra`                                   | Return address cannot be used as inputs or outputs.                                                                                                                                 |
 | Hexagon      | `lr`                                    | This is the link register which cannot be used as an input or output.                                                                                                               |
 | PowerPC      | `r2`, `r13`                             | These are system reserved registers.                                                                                                                                                |
-| PowerPC      | `lr`                                    | The link register cannot be used as an input or output.                                                                                                                             |
-| PowerPC      | `ctr`                                   | The counter register cannot be used as an input or output.                                                                                                                          |
 | PowerPC      | `vrsave`                                | The vrsave register cannot be used as an input or output.                                                                                                                           |
 | AVR          | `r0`, `r1`, `r1r0`                      | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs.  If modified, they must be restored to their original values before the end of the block. |
 |MSP430        | `r0`, `r2`, `r3`                        | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to.                          |
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index e204e1788ba..8feca1367fc 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -3,16 +3,16 @@
 // FIXME: Once the portability lint RFC is implemented (see tracking issue #41619),
 // switch to use those structures instead.
 
-use std::fmt::{self, Write};
-use std::{mem, ops};
+use std::{fmt, mem, ops};
 
+use itertools::Either;
 use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_session::parse::ParseSess;
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
 
-use crate::display::Joined as _;
+use crate::display::{Joined as _, MaybeDisplay, Wrapped};
 use crate::html::escape::Escape;
 
 #[cfg(test)]
@@ -376,27 +376,20 @@ impl Format {
             Format::LongPlain => false,
         }
     }
+
+    fn escape(self, s: &str) -> impl fmt::Display {
+        if self.is_html() { Either::Left(Escape(s)) } else { Either::Right(s) }
+    }
 }
 
 /// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used.
 struct Display<'a>(&'a Cfg, Format);
 
-fn write_with_opt_paren<T: fmt::Display>(
-    fmt: &mut fmt::Formatter<'_>,
-    has_paren: bool,
-    obj: T,
-) -> fmt::Result {
-    if has_paren {
-        fmt.write_char('(')?;
-    }
-    obj.fmt(fmt)?;
-    if has_paren {
-        fmt.write_char(')')?;
+impl Display<'_> {
+    fn code_wrappers(&self) -> Wrapped<&'static str> {
+        if self.1.is_html() { Wrapped::with("<code>", "</code>") } else { Wrapped::with("`", "`") }
     }
-    Ok(())
-}
 
-impl Display<'_> {
     fn display_sub_cfgs(
         &self,
         fmt: &mut fmt::Formatter<'_>,
@@ -427,20 +420,17 @@ impl Display<'_> {
             sub_cfgs
                 .iter()
                 .map(|sub_cfg| {
-                    fmt::from_fn(move |fmt| {
-                        if let Cfg::Cfg(_, Some(feat)) = sub_cfg
-                            && short_longhand
-                        {
-                            if self.1.is_html() {
-                                write!(fmt, "<code>{feat}</code>")?;
-                            } else {
-                                write!(fmt, "`{feat}`")?;
-                            }
-                        } else {
-                            write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
-                        }
-                        Ok(())
-                    })
+                    if let Cfg::Cfg(_, Some(feat)) = sub_cfg
+                        && short_longhand
+                    {
+                        Either::Left(self.code_wrappers().wrap(feat))
+                    } else {
+                        Either::Right(
+                            Wrapped::with_parens()
+                                .when(!sub_cfg.is_all())
+                                .wrap(Display(sub_cfg, self.1)),
+                        )
+                    }
                 })
                 .joined(separator, f)
         })
@@ -461,9 +451,9 @@ impl fmt::Display for Display<'_> {
                 sub_cfgs
                     .iter()
                     .map(|sub_cfg| {
-                        fmt::from_fn(|fmt| {
-                            write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))
-                        })
+                        Wrapped::with_parens()
+                            .when(!sub_cfg.is_all())
+                            .wrap(Display(sub_cfg, self.1))
                     })
                     .joined(separator, fmt)
             }
@@ -568,21 +558,13 @@ impl fmt::Display for Display<'_> {
                 };
                 if !human_readable.is_empty() {
                     fmt.write_str(human_readable)
-                } else if let Some(v) = value {
-                    if self.1.is_html() {
-                        write!(
-                            fmt,
-                            r#"<code>{}="{}"</code>"#,
-                            Escape(name.as_str()),
-                            Escape(v.as_str())
-                        )
-                    } else {
-                        write!(fmt, r#"`{name}="{v}"`"#)
-                    }
-                } else if self.1.is_html() {
-                    write!(fmt, "<code>{}</code>", Escape(name.as_str()))
                 } else {
-                    write!(fmt, "`{name}`")
+                    let value = value
+                        .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))))
+                        .maybe_display();
+                    self.code_wrappers()
+                        .wrap(format_args!("{}{value}", self.1.escape(name.as_str())))
+                        .fmt(fmt)
                 }
             }
         }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index bd3f4e9a6f2..ff513c71035 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -794,50 +794,6 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    /// Get a list of attributes excluding `#[repr]` to display.
-    ///
-    /// Only used by the HTML output-format.
-    fn attributes_without_repr(&self) -> Vec<String> {
-        self.attrs
-            .other_attrs
-            .iter()
-            .filter_map(|attr| match attr {
-                hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
-                    Some(format!("#[unsafe(link_section = \"{name}\")]"))
-                }
-                hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
-                    Some("#[unsafe(no_mangle)]".to_string())
-                }
-                hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
-                    Some(format!("#[unsafe(export_name = \"{name}\")]"))
-                }
-                hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
-                    Some("#[non_exhaustive]".to_string())
-                }
-                _ => None,
-            })
-            .collect()
-    }
-
-    /// Get a list of attributes to display on this item.
-    ///
-    /// Only used by the HTML output-format.
-    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
-        let mut attrs = self.attributes_without_repr();
-
-        if let Some(repr_attr) = self.repr(tcx, cache) {
-            attrs.push(repr_attr);
-        }
-        attrs
-    }
-
-    /// Returns a stringified `#[repr(...)]` attribute.
-    ///
-    /// Only used by the HTML output-format.
-    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
-        repr_attributes(tcx, cache, self.def_id()?, self.type_())
-    }
-
     pub fn is_doc_hidden(&self) -> bool {
         self.attrs.is_doc_hidden()
     }
@@ -847,74 +803,6 @@ impl Item {
     }
 }
 
-/// Return a string representing the `#[repr]` attribute if present.
-///
-/// Only used by the HTML output-format.
-pub(crate) fn repr_attributes(
-    tcx: TyCtxt<'_>,
-    cache: &Cache,
-    def_id: DefId,
-    item_type: ItemType,
-) -> Option<String> {
-    use rustc_abi::IntegerType;
-
-    if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
-        return None;
-    }
-    let adt = tcx.adt_def(def_id);
-    let repr = adt.repr();
-    let mut out = Vec::new();
-    if repr.c() {
-        out.push("C");
-    }
-    if repr.transparent() {
-        // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
-        // field is public in case all fields are 1-ZST fields.
-        let render_transparent = cache.document_private
-            || adt
-                .all_fields()
-                .find(|field| {
-                    let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
-                    tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
-                        .is_ok_and(|layout| !layout.is_1zst())
-                })
-                .map_or_else(
-                    || adt.all_fields().any(|field| field.vis.is_public()),
-                    |field| field.vis.is_public(),
-                );
-
-        if render_transparent {
-            out.push("transparent");
-        }
-    }
-    if repr.simd() {
-        out.push("simd");
-    }
-    let pack_s;
-    if let Some(pack) = repr.pack {
-        pack_s = format!("packed({})", pack.bytes());
-        out.push(&pack_s);
-    }
-    let align_s;
-    if let Some(align) = repr.align {
-        align_s = format!("align({})", align.bytes());
-        out.push(&align_s);
-    }
-    let int_s;
-    if let Some(int) = repr.int {
-        int_s = match int {
-            IntegerType::Pointer(is_signed) => {
-                format!("{}size", if is_signed { 'i' } else { 'u' })
-            }
-            IntegerType::Fixed(size, is_signed) => {
-                format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
-            }
-        };
-        out.push(&int_s);
-    }
-    if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
-}
-
 #[derive(Clone, Debug)]
 pub(crate) enum ItemKind {
     ExternCrateItem {
diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs
index db868c5c9a8..d62ea4c3688 100644
--- a/src/librustdoc/display.rs
+++ b/src/librustdoc/display.rs
@@ -1,6 +1,6 @@
 //! Various utilities for working with [`fmt::Display`] implementations.
 
-use std::fmt::{self, Display, Formatter};
+use std::fmt::{self, Display, Formatter, FormattingOptions};
 
 pub(crate) trait Joined: IntoIterator {
     /// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`.
@@ -45,3 +45,87 @@ impl<T: Display> MaybeDisplay for Option<T> {
         })
     }
 }
+
+#[derive(Clone, Copy)]
+pub(crate) struct Wrapped<T> {
+    prefix: T,
+    suffix: T,
+}
+
+pub(crate) enum AngleBracket {
+    Open,
+    Close,
+}
+
+impl Display for AngleBracket {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.write_str(match (self, f.alternate()) {
+            (Self::Open, true) => "<",
+            (Self::Open, false) => "&lt;",
+            (Self::Close, true) => ">",
+            (Self::Close, false) => "&gt;",
+        })
+    }
+}
+
+impl Wrapped<AngleBracket> {
+    pub(crate) fn with_angle_brackets() -> Self {
+        Self { prefix: AngleBracket::Open, suffix: AngleBracket::Close }
+    }
+}
+
+impl Wrapped<char> {
+    pub(crate) fn with_parens() -> Self {
+        Self { prefix: '(', suffix: ')' }
+    }
+
+    pub(crate) fn with_square_brackets() -> Self {
+        Self { prefix: '[', suffix: ']' }
+    }
+}
+
+impl<T: Display> Wrapped<T> {
+    pub(crate) fn with(prefix: T, suffix: T) -> Self {
+        Self { prefix, suffix }
+    }
+
+    pub(crate) fn when(self, if_: bool) -> Wrapped<impl Display> {
+        Wrapped {
+            prefix: if_.then_some(self.prefix).maybe_display(),
+            suffix: if_.then_some(self.suffix).maybe_display(),
+        }
+    }
+
+    pub(crate) fn wrap_fn(
+        self,
+        content: impl Fn(&mut Formatter<'_>) -> fmt::Result,
+    ) -> impl Display {
+        fmt::from_fn(move |f| {
+            self.prefix.fmt(f)?;
+            content(f)?;
+            self.suffix.fmt(f)
+        })
+    }
+
+    pub(crate) fn wrap<C: Display>(self, content: C) -> impl Display {
+        self.wrap_fn(move |f| content.fmt(f))
+    }
+}
+
+#[derive(Clone, Copy)]
+pub(crate) struct WithOpts {
+    opts: FormattingOptions,
+}
+
+impl WithOpts {
+    pub(crate) fn from(f: &Formatter<'_>) -> Self {
+        Self { opts: f.options() }
+    }
+
+    pub(crate) fn display(self, t: impl Display) -> impl Display {
+        fmt::from_fn(move |f| {
+            let mut f = f.with_options(self.opts);
+            t.fmt(&mut f)
+        })
+    }
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8c75f301841..ecaff4cdf43 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -30,7 +30,7 @@ use super::url_parts_builder::UrlPartsBuilder;
 use crate::clean::types::ExternalLocation;
 use crate::clean::utils::find_nearest_parent_module;
 use crate::clean::{self, ExternalCrate, PrimitiveType};
-use crate::display::{Joined as _, MaybeDisplay as _};
+use crate::display::{Joined as _, MaybeDisplay as _, WithOpts, Wrapped};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyText};
@@ -105,20 +105,16 @@ impl clean::GenericParamDef {
 
 impl clean::Generics {
     pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| {
-            let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
-            if real_params.peek().is_none() {
-                return Ok(());
-            }
-
-            let real_params =
-                fmt::from_fn(|f| real_params.clone().map(|g| g.print(cx)).joined(", ", f));
-            if f.alternate() {
-                write!(f, "<{real_params:#}>")
-            } else {
-                write!(f, "&lt;{real_params}&gt;")
-            }
-        })
+        let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
+        if real_params.peek().is_none() {
+            None
+        } else {
+            Some(
+                Wrapped::with_angle_brackets()
+                    .wrap_fn(move |f| real_params.clone().map(|g| g.print(cx)).joined(", ", f)),
+            )
+        }
+        .maybe_display()
     }
 }
 
@@ -151,11 +147,8 @@ fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) ->
                 Ok(())
             }
             clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                if f.alternate() {
-                    write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
-                } else {
-                    write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
-                }
+                let opts = WithOpts::from(f);
+                write!(f, "{} == {}", opts.display(lhs.print(cx)), opts.display(rhs.print(cx)))
             }
         }
     })
@@ -279,13 +272,10 @@ impl clean::GenericBound {
                 ty.print(cx).fmt(f)
             }
             clean::GenericBound::Use(args) => {
-                if f.alternate() {
-                    f.write_str("use<")?;
-                } else {
-                    f.write_str("use&lt;")?;
-                }
-                args.iter().map(|arg| arg.name()).joined(", ", f)?;
-                if f.alternate() { f.write_str(">") } else { f.write_str("&gt;") }
+                f.write_str("use")?;
+                Wrapped::with_angle_brackets()
+                    .wrap_fn(|f| args.iter().map(|arg| arg.name()).joined(", ", f))
+                    .fmt(f)
             }
         })
     }
@@ -297,40 +287,29 @@ impl clean::GenericArgs {
             match self {
                 clean::GenericArgs::AngleBracketed { args, constraints } => {
                     if !args.is_empty() || !constraints.is_empty() {
-                        if f.alternate() {
-                            f.write_str("<")?;
-                        } else {
-                            f.write_str("&lt;")?;
-                        }
-
-                        [Either::Left(args), Either::Right(constraints)]
-                            .into_iter()
-                            .flat_map(Either::factor_into_iter)
-                            .map(|either| {
-                                either.map_either(
-                                    |arg| arg.print(cx),
-                                    |constraint| constraint.print(cx),
-                                )
+                        Wrapped::with_angle_brackets()
+                            .wrap_fn(|f| {
+                                [Either::Left(args), Either::Right(constraints)]
+                                    .into_iter()
+                                    .flat_map(Either::factor_into_iter)
+                                    .map(|either| {
+                                        either.map_either(
+                                            |arg| arg.print(cx),
+                                            |constraint| constraint.print(cx),
+                                        )
+                                    })
+                                    .joined(", ", f)
                             })
-                            .joined(", ", f)?;
-
-                        if f.alternate() {
-                            f.write_str(">")?;
-                        } else {
-                            f.write_str("&gt;")?;
-                        }
+                            .fmt(f)?;
                     }
                 }
                 clean::GenericArgs::Parenthesized { inputs, output } => {
-                    f.write_str("(")?;
-                    inputs.iter().map(|ty| ty.print(cx)).joined(", ", f)?;
-                    f.write_str(")")?;
+                    Wrapped::with_parens()
+                        .wrap_fn(|f| inputs.iter().map(|ty| ty.print(cx)).joined(", ", f))
+                        .fmt(f)?;
                     if let Some(ref ty) = *output {
-                        if f.alternate() {
-                            write!(f, " -> {:#}", ty.print(cx))?;
-                        } else {
-                            write!(f, " -&gt; {}", ty.print(cx))?;
-                        }
+                        f.write_str(if f.alternate() { " -> " } else { " -&gt; " })?;
+                        ty.print(cx).fmt(f)?;
                     }
                 }
                 clean::GenericArgs::ReturnTypeNotation => {
@@ -834,9 +813,10 @@ fn print_higher_ranked_params_with_space(
     fmt::from_fn(move |f| {
         if !params.is_empty() {
             f.write_str(keyword)?;
-            f.write_str(if f.alternate() { "<" } else { "&lt;" })?;
-            params.iter().map(|lt| lt.print(cx)).joined(", ", f)?;
-            f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
+            Wrapped::with_angle_brackets()
+                .wrap_fn(|f| params.iter().map(|lt| lt.print(cx)).joined(", ", f))
+                .fmt(f)?;
+            f.write_char(' ')?;
         }
         Ok(())
     })
@@ -923,26 +903,23 @@ fn fmt_type(
                         f,
                         PrimitiveType::Tuple,
                         format_args!(
-                            "({})",
-                            fmt::from_fn(|f| generic_names.iter().joined(", ", f))
+                            "{}",
+                            Wrapped::with_parens()
+                                .wrap_fn(|f| generic_names.iter().joined(", ", f))
                         ),
                         cx,
                     )
                 } else {
-                    f.write_str("(")?;
-                    many.iter().map(|item| item.print(cx)).joined(", ", f)?;
-                    f.write_str(")")
+                    Wrapped::with_parens()
+                        .wrap_fn(|f| many.iter().map(|item| item.print(cx)).joined(", ", f))
+                        .fmt(f)
                 }
             }
         },
         clean::Slice(box clean::Generic(name)) => {
             primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx)
         }
-        clean::Slice(t) => {
-            write!(f, "[")?;
-            t.print(cx).fmt(f)?;
-            write!(f, "]")
-        }
+        clean::Slice(t) => Wrapped::with_square_brackets().wrap(t.print(cx)).fmt(f),
         clean::Type::Pat(t, pat) => {
             fmt::Display::fmt(&t.print(cx), f)?;
             write!(f, " is {pat}")
@@ -953,40 +930,27 @@ fn fmt_type(
             format_args!("[{name}; {n}]", n = Escape(n)),
             cx,
         ),
-        clean::Array(t, n) => {
-            write!(f, "[")?;
-            t.print(cx).fmt(f)?;
-            if f.alternate() {
-                write!(f, "; {n}")?;
-            } else {
-                write!(f, "; ")?;
-                primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)?;
-            }
-            write!(f, "]")
-        }
-        clean::RawPointer(m, t) => {
-            let m = match m {
-                hir::Mutability::Mut => "mut",
-                hir::Mutability::Not => "const",
-            };
-
-            if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
-                let ty = t.print(cx);
+        clean::Array(t, n) => Wrapped::with_square_brackets()
+            .wrap(fmt::from_fn(|f| {
+                t.print(cx).fmt(f)?;
+                f.write_str("; ")?;
                 if f.alternate() {
-                    primitive_link(
-                        f,
-                        clean::PrimitiveType::RawPointer,
-                        format_args!("*{m} {ty:#}"),
-                        cx,
-                    )
+                    f.write_str(n)
                 } else {
-                    primitive_link(
-                        f,
-                        clean::PrimitiveType::RawPointer,
-                        format_args!("*{m} {ty}"),
-                        cx,
-                    )
+                    primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)
                 }
+            }))
+            .fmt(f),
+        clean::RawPointer(m, t) => {
+            let m = m.ptr_str();
+
+            if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
+                primitive_link(
+                    f,
+                    clean::PrimitiveType::RawPointer,
+                    format_args!("*{m} {ty}", ty = WithOpts::from(f).display(t.print(cx))),
+                    cx,
+                )
             } else {
                 primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?;
                 t.print(cx).fmt(f)
@@ -1020,14 +984,10 @@ fn fmt_type(
                 clean::ImplTrait(ref bounds) if bounds.len() > 1 => true,
                 _ => false,
             };
-            if needs_parens {
-                f.write_str("(")?;
-            }
-            fmt_type(ty, f, use_absolute, cx)?;
-            if needs_parens {
-                f.write_str(")")?;
-            }
-            Ok(())
+            Wrapped::with_parens()
+                .when(needs_parens)
+                .wrap_fn(|f| fmt_type(ty, f, use_absolute, cx))
+                .fmt(f)
         }
         clean::ImplTrait(bounds) => {
             f.write_str("impl ")?;
@@ -1057,23 +1017,21 @@ impl clean::QPathData {
             // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719),
             // we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`).
 
-            if f.alternate() {
-                if let Some(trait_) = trait_
-                    && should_fully_qualify
-                {
-                    write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
-                } else {
-                    write!(f, "{:#}::", self_type.print(cx))?
-                }
+            if let Some(trait_) = trait_
+                && should_fully_qualify
+            {
+                let opts = WithOpts::from(f);
+                Wrapped::with_angle_brackets()
+                    .wrap(format_args!(
+                        "{} as {}",
+                        opts.display(self_type.print(cx)),
+                        opts.display(trait_.print(cx))
+                    ))
+                    .fmt(f)?
             } else {
-                if let Some(trait_) = trait_
-                    && should_fully_qualify
-                {
-                    write!(f, "&lt;{} as {}&gt;::", self_type.print(cx), trait_.print(cx))?
-                } else {
-                    write!(f, "{}::", self_type.print(cx))?
-                }
-            };
+                self_type.print(cx).fmt(f)?;
+            }
+            f.write_str("::")?;
             // It's pretty unsightly to look at `<A as B>::C` in output, and
             // we've got hyperlinking on our side, so try to avoid longer
             // notation as much as possible by making `C` a hyperlink to trait
@@ -1132,7 +1090,7 @@ impl clean::Impl {
 
             if let Some(ref ty) = self.trait_ {
                 if self.is_negative_trait_impl() {
-                    write!(f, "!")?;
+                    f.write_char('!')?;
                 }
                 if self.kind.is_fake_variadic()
                     && let Some(generics) = ty.generics()
@@ -1140,18 +1098,17 @@ impl clean::Impl {
                 {
                     let last = ty.last();
                     if f.alternate() {
-                        write!(f, "{last}<")?;
-                        self.print_type(inner_type, f, use_absolute, cx)?;
-                        write!(f, ">")?;
+                        write!(f, "{last}")?;
                     } else {
-                        write!(f, "{}&lt;", print_anchor(ty.def_id(), last, cx))?;
-                        self.print_type(inner_type, f, use_absolute, cx)?;
-                        write!(f, "&gt;")?;
-                    }
+                        write!(f, "{}", print_anchor(ty.def_id(), last, cx))?;
+                    };
+                    Wrapped::with_angle_brackets()
+                        .wrap_fn(|f| self.print_type(inner_type, f, use_absolute, cx))
+                        .fmt(f)?;
                 } else {
                     ty.print(cx).fmt(f)?;
                 }
-                write!(f, " for ")?;
+                f.write_str(" for ")?;
             }
 
             if let Some(ty) = self.kind.as_blanket_ty() {
@@ -1218,18 +1175,10 @@ impl clean::Impl {
             && let Ok(ty) = generics.exactly_one()
             && self.kind.is_fake_variadic()
         {
-            let wrapper = print_anchor(path.def_id(), path.last(), cx);
-            if f.alternate() {
-                write!(f, "{wrapper:#}&lt;")?;
-            } else {
-                write!(f, "{wrapper}<")?;
-            }
-            self.print_type(ty, f, use_absolute, cx)?;
-            if f.alternate() {
-                write!(f, "&gt;")?;
-            } else {
-                write!(f, ">")?;
-            }
+            print_anchor(path.def_id(), path.last(), cx).fmt(f)?;
+            Wrapped::with_angle_brackets()
+                .wrap_fn(|f| self.print_type(ty, f, use_absolute, cx))
+                .fmt(f)?;
         } else {
             fmt_type(type_, f, use_absolute, cx)?;
         }
@@ -1311,23 +1260,13 @@ impl clean::FnDecl {
     pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
-            if f.alternate() {
-                write!(
-                    f,
-                    "({params:#}{ellipsis}){arrow:#}",
-                    params = print_params(&self.inputs, cx),
-                    ellipsis = ellipsis,
-                    arrow = self.print_output(cx)
-                )
-            } else {
-                write!(
-                    f,
-                    "({params}{ellipsis}){arrow}",
-                    params = print_params(&self.inputs, cx),
-                    ellipsis = ellipsis,
-                    arrow = self.print_output(cx)
-                )
-            }
+            Wrapped::with_parens()
+                .wrap_fn(|f| {
+                    print_params(&self.inputs, cx).fmt(f)?;
+                    f.write_str(ellipsis)
+                })
+                .fmt(f)?;
+            self.print_output(cx).fmt(f)
         })
     }
 
@@ -1346,8 +1285,7 @@ impl clean::FnDecl {
         fmt::from_fn(move |f| {
             // First, generate the text form of the declaration, with no line wrapping, and count the bytes.
             let mut counter = WriteCounter(0);
-            write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))
-                .unwrap();
+            write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))?;
             // If the text form was over 80 characters wide, we will line-wrap our output.
             let line_wrapping_indent =
                 if header_len + counter.0 > 80 { Some(indent) } else { None };
@@ -1365,53 +1303,56 @@ impl clean::FnDecl {
         f: &mut fmt::Formatter<'_>,
         cx: &Context<'_>,
     ) -> fmt::Result {
-        f.write_char('(')?;
+        Wrapped::with_parens()
+            .wrap_fn(|f| {
+                if !self.inputs.is_empty() {
+                    let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4));
 
-        if !self.inputs.is_empty() {
-            let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4));
-
-            if let Some(indent) = line_wrapping_indent {
-                write!(f, "\n{indent}")?;
-            }
+                    if let Some(indent) = line_wrapping_indent {
+                        write!(f, "\n{indent}")?;
+                    }
 
-            let sep = fmt::from_fn(|f| {
-                if let Some(indent) = line_wrapping_indent {
-                    write!(f, ",\n{indent}")
-                } else {
-                    f.write_str(", ")
-                }
-            });
+                    let sep = fmt::from_fn(|f| {
+                        if let Some(indent) = line_wrapping_indent {
+                            write!(f, ",\n{indent}")
+                        } else {
+                            f.write_str(", ")
+                        }
+                    });
 
-            self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?;
+                    self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?;
 
-            if line_wrapping_indent.is_some() {
-                writeln!(f, ",")?
-            }
+                    if line_wrapping_indent.is_some() {
+                        writeln!(f, ",")?
+                    }
 
-            if self.c_variadic {
-                match line_wrapping_indent {
-                    None => write!(f, ", ...")?,
-                    Some(indent) => writeln!(f, "{indent}...")?,
-                };
-            }
-        }
+                    if self.c_variadic {
+                        match line_wrapping_indent {
+                            None => write!(f, ", ...")?,
+                            Some(indent) => writeln!(f, "{indent}...")?,
+                        };
+                    }
+                }
 
-        if let Some(n) = line_wrapping_indent {
-            write!(f, "{}", Indent(n))?
-        }
+                if let Some(n) = line_wrapping_indent {
+                    write!(f, "{}", Indent(n))?
+                }
 
-        f.write_char(')')?;
+                Ok(())
+            })
+            .fmt(f)?;
 
         self.print_output(cx).fmt(f)
     }
 
     fn print_output(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| match &self.output {
-            clean::Tuple(tys) if tys.is_empty() => Ok(()),
-            ty if f.alternate() => {
-                write!(f, " -> {:#}", ty.print(cx))
+        fmt::from_fn(move |f| {
+            if self.output.is_unit() {
+                return Ok(());
             }
-            ty => write!(f, " -&gt; {}", ty.print(cx)),
+
+            f.write_str(if f.alternate() { " -> " } else { " -&gt; " })?;
+            self.output.print(cx).fmt(f)
         })
     }
 }
@@ -1422,10 +1363,13 @@ pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>)
             f.write_str("#[doc(hidden)] ")?;
         }
 
-        match item.visibility(cx.tcx()) {
-            None => {}
-            Some(ty::Visibility::Public) => f.write_str("pub ")?,
-            Some(ty::Visibility::Restricted(vis_did)) => {
+        let Some(vis) = item.visibility(cx.tcx()) else {
+            return Ok(());
+        };
+
+        match vis {
+            ty::Visibility::Public => f.write_str("pub ")?,
+            ty::Visibility::Restricted(vis_did) => {
                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
                 //                 However, rustdoc currently never displays a module's
                 //                 visibility, so it shouldn't matter.
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 0e06361024b..fad15573cde 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -8,6 +8,7 @@
 use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt::{self, Display, Write};
+use std::iter;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
@@ -15,8 +16,9 @@ use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, DUMMY_SP, Span};
 
-use super::format::{self, write_str};
+use super::format;
 use crate::clean::PrimitiveType;
+use crate::display::Joined as _;
 use crate::html::escape::EscapeBodyText;
 use crate::html::macro_expansion::ExpandedCode;
 use crate::html::render::{Context, LinkFromSrc};
@@ -45,92 +47,72 @@ pub(crate) enum Tooltip {
     CompileFail,
     ShouldPanic,
     Edition(Edition),
-    None,
 }
 
 /// Highlights `src` as an inline example, returning the HTML output.
 pub(crate) fn render_example_with_highlighting(
     src: &str,
-    out: &mut String,
-    tooltip: Tooltip,
+    tooltip: Option<&Tooltip>,
     playground_button: Option<&str>,
     extra_classes: &[String],
-) {
-    write_header(out, "rust-example-rendered", None, tooltip, extra_classes);
-    write_code(out, src, None, None, None);
-    write_footer(out, playground_button);
+) -> impl Display {
+    fmt::from_fn(move |f| {
+        write_header("rust-example-rendered", tooltip, extra_classes).fmt(f)?;
+        write_code(f, src, None, None, None);
+        write_footer(playground_button).fmt(f)
+    })
 }
 
-fn write_header(
-    out: &mut String,
-    class: &str,
-    extra_content: Option<&str>,
-    tooltip: Tooltip,
-    extra_classes: &[String],
-) {
-    write_str(
-        out,
-        format_args!(
+fn write_header(class: &str, tooltip: Option<&Tooltip>, extra_classes: &[String]) -> impl Display {
+    fmt::from_fn(move |f| {
+        write!(
+            f,
             "<div class=\"example-wrap{}\">",
-            match tooltip {
-                Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
-                Tooltip::CompileFail => " compile_fail",
-                Tooltip::ShouldPanic => " should_panic",
-                Tooltip::Edition(_) => " edition",
-                Tooltip::None => "",
-            }
-        ),
-    );
-
-    if tooltip != Tooltip::None {
-        let tooltip = fmt::from_fn(|f| match &tooltip {
-            Tooltip::IgnoreAll => f.write_str("This example is not tested"),
-            Tooltip::IgnoreSome(platforms) => {
-                f.write_str("This example is not tested on ")?;
-                match &platforms[..] {
-                    [] => unreachable!(),
-                    [platform] => f.write_str(platform)?,
-                    [first, second] => write!(f, "{first} or {second}")?,
-                    [platforms @ .., last] => {
-                        for platform in platforms {
-                            write!(f, "{platform}, ")?;
+            tooltip
+                .map(|tooltip| match tooltip {
+                    Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
+                    Tooltip::CompileFail => " compile_fail",
+                    Tooltip::ShouldPanic => " should_panic",
+                    Tooltip::Edition(_) => " edition",
+                })
+                .unwrap_or_default()
+        )?;
+
+        if let Some(tooltip) = tooltip {
+            let tooltip = fmt::from_fn(|f| match tooltip {
+                Tooltip::IgnoreAll => f.write_str("This example is not tested"),
+                Tooltip::IgnoreSome(platforms) => {
+                    f.write_str("This example is not tested on ")?;
+                    match &platforms[..] {
+                        [] => unreachable!(),
+                        [platform] => f.write_str(platform)?,
+                        [first, second] => write!(f, "{first} or {second}")?,
+                        [platforms @ .., last] => {
+                            for platform in platforms {
+                                write!(f, "{platform}, ")?;
+                            }
+                            write!(f, "or {last}")?;
                         }
-                        write!(f, "or {last}")?;
                     }
+                    Ok(())
                 }
-                Ok(())
-            }
-            Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
-            Tooltip::ShouldPanic => f.write_str("This example panics"),
-            Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
-            Tooltip::None => unreachable!(),
+                Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
+                Tooltip::ShouldPanic => f.write_str("This example panics"),
+                Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
+            });
+
+            write!(f, "<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>")?;
+        }
+
+        let classes = fmt::from_fn(|f| {
+            iter::once("rust")
+                .chain(Some(class).filter(|class| !class.is_empty()))
+                .chain(extra_classes.iter().map(String::as_str))
+                .joined(" ", f)
         });
-        write_str(out, format_args!("<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>"));
-    }
 
-    if let Some(extra) = extra_content {
-        out.push_str(extra);
-    }
-    if class.is_empty() {
-        write_str(
-            out,
-            format_args!(
-                "<pre class=\"rust{}{}\">",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    } else {
-        write_str(
-            out,
-            format_args!(
-                "<pre class=\"rust {class}{}{}\">",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    }
-    write_str(out, format_args!("<code>"));
+        write!(f, "<pre class=\"{classes}\"><code>")
+    })
 }
 
 /// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -577,8 +559,8 @@ pub(super) fn write_code(
     });
 }
 
-fn write_footer(out: &mut String, playground_button: Option<&str>) {
-    write_str(out, format_args!("</code></pre>{}</div>", playground_button.unwrap_or_default()));
+fn write_footer(playground_button: Option<&str>) -> impl Display {
+    fmt::from_fn(move |f| write!(f, "</code></pre>{}</div>", playground_button.unwrap_or_default()))
 }
 
 /// How a span of text is classified. Mostly corresponds to token kinds.
@@ -1262,6 +1244,64 @@ fn string<W: Write>(
     }
 }
 
+fn generate_link_to_def(
+    out: &mut impl Write,
+    text_s: &str,
+    klass: Class,
+    href_context: &Option<HrefContext<'_, '_>>,
+    def_span: Span,
+    open_tag: bool,
+) -> bool {
+    if let Some(href_context) = href_context
+        && let Some(href) =
+            href_context.context.shared.span_correspondence_map.get(&def_span).and_then(|href| {
+                let context = href_context.context;
+                // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
+                // one to the documentation page and one to the source definition.
+                // FIXME: currently, external items only generate a link to their documentation,
+                // a link to their definition can be generated using this:
+                // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
+                match href {
+                    LinkFromSrc::Local(span) => {
+                        context.href_from_span_relative(*span, &href_context.current_href)
+                    }
+                    LinkFromSrc::External(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                            .ok()
+                            .map(|(url, _, _)| url)
+                    }
+                    LinkFromSrc::Primitive(prim) => format::href_with_root_path(
+                        PrimitiveType::primitive_locations(context.tcx())[prim],
+                        context,
+                        Some(href_context.root_path),
+                    )
+                    .ok()
+                    .map(|(url, _, _)| url),
+                    LinkFromSrc::Doc(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                            .ok()
+                            .map(|(doc_link, _, _)| doc_link)
+                    }
+                }
+            })
+    {
+        if !open_tag {
+            // We're already inside an element which has the same klass, no need to give it
+            // again.
+            write!(out, "<a href=\"{href}\">{text_s}").unwrap();
+        } else {
+            let klass_s = klass.as_html();
+            if klass_s.is_empty() {
+                write!(out, "<a href=\"{href}\">{text_s}").unwrap();
+            } else {
+                write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
+            }
+        }
+        return true;
+    }
+    false
+}
+
 /// This function writes `text` into `out` with some modifications depending on `klass`:
 ///
 /// * If `klass` is `None`, `text` is written into `out` with no modification.
@@ -1291,10 +1331,14 @@ fn string_without_closing_tag<T: Display>(
         return Some("</span>");
     };
 
+    let mut added_links = false;
     let mut text_s = text.to_string();
     if text_s.contains("::") {
+        let mut span = def_span.with_hi(def_span.lo());
         text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
+            span = span.with_hi(span.hi() + BytePos(t.len() as _));
             match t {
+                "::" => write!(&mut path, "::"),
                 "self" | "Self" => write!(
                     &mut path,
                     "<span class=\"{klass}\">{t}</span>",
@@ -1307,58 +1351,24 @@ fn string_without_closing_tag<T: Display>(
                         klass = Class::KeyWord.as_html(),
                     )
                 }
-                t => write!(&mut path, "{t}"),
+                t => {
+                    if !t.is_empty()
+                        && generate_link_to_def(&mut path, t, klass, href_context, span, open_tag)
+                    {
+                        added_links = true;
+                        write!(&mut path, "</a>")
+                    } else {
+                        write!(&mut path, "{t}")
+                    }
+                }
             }
             .expect("Failed to build source HTML path");
+            span = span.with_lo(span.lo() + BytePos(t.len() as _));
             path
         });
     }
 
-    if let Some(href_context) = href_context
-        && let Some(href) = href_context.context.shared.span_correspondence_map.get(&def_span)
-        && let Some(href) = {
-            let context = href_context.context;
-            // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
-            // one to the documentation page and one to the source definition.
-            // FIXME: currently, external items only generate a link to their documentation,
-            // a link to their definition can be generated using this:
-            // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
-            match href {
-                LinkFromSrc::Local(span) => {
-                    context.href_from_span_relative(*span, &href_context.current_href)
-                }
-                LinkFromSrc::External(def_id) => {
-                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                        .ok()
-                        .map(|(url, _, _)| url)
-                }
-                LinkFromSrc::Primitive(prim) => format::href_with_root_path(
-                    PrimitiveType::primitive_locations(context.tcx())[prim],
-                    context,
-                    Some(href_context.root_path),
-                )
-                .ok()
-                .map(|(url, _, _)| url),
-                LinkFromSrc::Doc(def_id) => {
-                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                        .ok()
-                        .map(|(doc_link, _, _)| doc_link)
-                }
-            }
-        }
-    {
-        if !open_tag {
-            // We're already inside an element which has the same klass, no need to give it
-            // again.
-            write!(out, "<a href=\"{href}\">{text_s}").unwrap();
-        } else {
-            let klass_s = klass.as_html();
-            if klass_s.is_empty() {
-                write!(out, "<a href=\"{href}\">{text_s}").unwrap();
-            } else {
-                write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
-            }
-        }
+    if !added_links && generate_link_to_def(out, &text_s, klass, href_context, def_span, open_tag) {
         return Some("</a>");
     }
     if !open_tag {
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 4addf2c3c96..7065de14c8e 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -321,31 +321,34 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             ))
         });
 
-        let tooltip = if ignore == Ignore::All {
-            highlight::Tooltip::IgnoreAll
-        } else if let Ignore::Some(platforms) = ignore {
-            highlight::Tooltip::IgnoreSome(platforms)
-        } else if compile_fail {
-            highlight::Tooltip::CompileFail
-        } else if should_panic {
-            highlight::Tooltip::ShouldPanic
-        } else if explicit_edition {
-            highlight::Tooltip::Edition(edition)
-        } else {
-            highlight::Tooltip::None
+        let tooltip = {
+            use highlight::Tooltip::*;
+
+            if ignore == Ignore::All {
+                Some(IgnoreAll)
+            } else if let Ignore::Some(platforms) = ignore {
+                Some(IgnoreSome(platforms))
+            } else if compile_fail {
+                Some(CompileFail)
+            } else if should_panic {
+                Some(ShouldPanic)
+            } else if explicit_edition {
+                Some(Edition(edition))
+            } else {
+                None
+            }
         };
 
         // insert newline to clearly separate it from the
         // previous block so we can shorten the html output
-        let mut s = String::new();
-        s.push('\n');
-
-        highlight::render_example_with_highlighting(
-            &text,
-            &mut s,
-            tooltip,
-            playground_button.as_deref(),
-            &added_classes,
+        let s = format!(
+            "\n{}",
+            highlight::render_example_with_highlighting(
+                &text,
+                tooltip.as_ref(),
+                playground_button.as_deref(),
+                &added_classes,
+            )
         );
         Some(Event::Html(s.into()))
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 6d684449b6d..d06540a65b5 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -51,7 +51,9 @@ use askama::Template;
 use itertools::Either;
 use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_hir::attrs::{DeprecatedSince, Deprecation};
+use rustc_hir as hir;
+use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince};
 use rustc_middle::ty::print::PrintTraitRefExt;
@@ -601,7 +603,12 @@ impl AllTypes {
         }
 
         fmt::from_fn(|f| {
-            f.write_str("<h1>List of all items</h1>")?;
+            f.write_str(
+                "<div class=\"main-heading\">\
+                    <h1>List of all items</h1>\
+                    <rustdoc-toolbar></rustdoc-toolbar>\
+                </div>",
+            )?;
             // Note: print_entries does not escape the title, because we know the current set of titles
             // doesn't require escaping.
             print_entries(&self.structs, ItemSection::Structs).fmt(f)?;
@@ -1310,43 +1317,6 @@ fn render_assoc_item(
     })
 }
 
-struct CodeAttribute(String);
-
-fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) {
-    write!(
-        w,
-        "<div class=\"code-attribute\">{prefix}{attr}</div>",
-        prefix = prefix,
-        attr = code_attr.0
-    )
-    .unwrap();
-}
-
-// When an attribute is rendered inside a <code> tag, it is formatted using
-// a div to produce a newline after it.
-fn render_attributes_in_code(
-    w: &mut impl fmt::Write,
-    it: &clean::Item,
-    prefix: &str,
-    cx: &Context<'_>,
-) {
-    for attr in it.attributes(cx.tcx(), cx.cache()) {
-        render_code_attribute(prefix, CodeAttribute(attr), w);
-    }
-}
-
-/// used for type aliases to only render their `repr` attribute.
-fn render_repr_attributes_in_code(
-    w: &mut impl fmt::Write,
-    cx: &Context<'_>,
-    def_id: DefId,
-    item_type: ItemType,
-) {
-    if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
-        render_code_attribute("", CodeAttribute(repr), w);
-    }
-}
-
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
@@ -2959,3 +2929,142 @@ fn render_call_locations<W: fmt::Write>(
 
     w.write_str("</div>")
 }
+
+fn render_attributes_in_code(
+    w: &mut impl fmt::Write,
+    item: &clean::Item,
+    prefix: &str,
+    cx: &Context<'_>,
+) {
+    for attr in &item.attrs.other_attrs {
+        let hir::Attribute::Parsed(kind) = attr else { continue };
+        let attr = match kind {
+            AttributeKind::LinkSection { name, .. } => {
+                Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}"))))
+            }
+            AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"),
+            AttributeKind::ExportName { name, .. } => {
+                Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}"))))
+            }
+            AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"),
+            _ => continue,
+        };
+        render_code_attribute(prefix, attr.as_ref(), w);
+    }
+
+    if let Some(def_id) = item.def_id()
+        && let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id)
+    {
+        render_code_attribute(prefix, &repr, w);
+    }
+}
+
+fn render_repr_attribute_in_code(w: &mut impl fmt::Write, cx: &Context<'_>, def_id: DefId) {
+    if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) {
+        render_code_attribute("", &repr, w);
+    }
+}
+
+fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) {
+    write!(w, "<div class=\"code-attribute\">{prefix}{attr}</div>").unwrap();
+}
+
+/// Compute the *public* `#[repr]` of the item given by `DefId`.
+///
+/// Read more about it here:
+/// <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
+fn repr_attribute<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    cache: &Cache,
+    def_id: DefId,
+) -> Option<Cow<'static, str>> {
+    let adt = match tcx.def_kind(def_id) {
+        DefKind::Struct | DefKind::Enum | DefKind::Union => tcx.adt_def(def_id),
+        _ => return None,
+    };
+    let repr = adt.repr();
+
+    let is_visible = |def_id| cache.document_hidden || !tcx.is_doc_hidden(def_id);
+    let is_public_field = |field: &ty::FieldDef| {
+        (cache.document_private || field.vis.is_public()) && is_visible(field.did)
+    };
+
+    if repr.transparent() {
+        // The transparent repr is public iff the non-1-ZST field is public and visible or
+        // – in case all fields are 1-ZST fields — at least one field is public and visible.
+        let is_public = 'is_public: {
+            // `#[repr(transparent)]` can only be applied to structs and single-variant enums.
+            let var = adt.variant(rustc_abi::FIRST_VARIANT); // the first and only variant
+
+            if !is_visible(var.def_id) {
+                break 'is_public false;
+            }
+
+            // Side note: There can only ever be one or zero non-1-ZST fields.
+            let non_1zst_field = var.fields.iter().find(|field| {
+                let ty = ty::TypingEnv::post_analysis(tcx, field.did)
+                    .as_query_input(tcx.type_of(field.did).instantiate_identity());
+                tcx.layout_of(ty).is_ok_and(|layout| !layout.is_1zst())
+            });
+
+            match non_1zst_field {
+                Some(field) => is_public_field(field),
+                None => var.fields.is_empty() || var.fields.iter().any(is_public_field),
+            }
+        };
+
+        // Since the transparent repr can't have any other reprs or
+        // repr modifiers beside it, we can safely return early here.
+        return is_public.then(|| "#[repr(transparent)]".into());
+    }
+
+    // Fast path which avoids looking through the variants and fields in
+    // the common case of no `#[repr]` or in the case of `#[repr(Rust)]`.
+    // FIXME: This check is not very robust / forward compatible!
+    if !repr.c()
+        && !repr.simd()
+        && repr.int.is_none()
+        && repr.pack.is_none()
+        && repr.align.is_none()
+    {
+        return None;
+    }
+
+    // The repr is public iff all components are public and visible.
+    let is_public = adt
+        .variants()
+        .iter()
+        .all(|variant| is_visible(variant.def_id) && variant.fields.iter().all(is_public_field));
+    if !is_public {
+        return None;
+    }
+
+    let mut result = Vec::<Cow<'_, _>>::new();
+
+    if repr.c() {
+        result.push("C".into());
+    }
+    if repr.simd() {
+        result.push("simd".into());
+    }
+    if let Some(int) = repr.int {
+        let prefix = if int.is_signed() { 'i' } else { 'u' };
+        let int = match int {
+            rustc_abi::IntegerType::Pointer(_) => format!("{prefix}size"),
+            rustc_abi::IntegerType::Fixed(int, _) => {
+                format!("{prefix}{}", int.size().bytes() * 8)
+            }
+        };
+        result.push(int.into());
+    }
+
+    // Render modifiers last.
+    if let Some(pack) = repr.pack {
+        result.push(format!("packed({})", pack.bytes()).into());
+    }
+    if let Some(align) = repr.align {
+        result.push(format!("align({})", align.bytes()).into());
+    }
+
+    (!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into())
+}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index afa438f2596..adfc7481c73 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -21,7 +21,7 @@ use super::{
     collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
     item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
     render_assoc_item, render_assoc_items, render_attributes_in_code, render_impl,
-    render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
+    render_repr_attribute_in_code, render_rightside, render_stability_since_raw,
     render_stability_since_raw_with_extra, write_section_heading,
 };
 use crate::clean;
@@ -1555,7 +1555,7 @@ impl<'clean> DisplayEnum<'clean> {
         wrap_item(w, |w| {
             if is_type_alias {
                 // For now the only attributes we render for type aliases are `repr` attributes.
-                render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum);
+                render_repr_attribute_in_code(w, cx, self.def_id);
             } else {
                 render_attributes_in_code(w, it, "", cx);
             }
@@ -2017,7 +2017,7 @@ impl<'a> DisplayStruct<'a> {
         wrap_item(w, |w| {
             if is_type_alias {
                 // For now the only attributes we render for type aliases are `repr` attributes.
-                render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct);
+                render_repr_attribute_in_code(w, cx, self.def_id);
             } else {
                 render_attributes_in_code(w, it, "", cx);
             }
@@ -2371,7 +2371,7 @@ fn render_union(
     fmt::from_fn(move |mut f| {
         if is_type_alias {
             // For now the only attributes we render for type aliases are `repr` attributes.
-            render_repr_attributes_in_code(f, cx, def_id, ItemType::Union);
+            render_repr_attribute_in_code(f, cx, def_id);
         } else {
             render_attributes_in_code(f, it, "", cx);
         }
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 2984f3ab50e..3ffce61f7c6 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -6,6 +6,8 @@ use std::path::Path;
 
 use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::find_attr;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
@@ -1458,16 +1460,17 @@ pub(crate) fn build_index(
                     if fqp.last() != Some(&item.name) {
                         return None;
                     }
-                    let path =
-                        if item.ty == ItemType::Macro && tcx.has_attr(defid, sym::macro_export) {
-                            // `#[macro_export]` always exports to the crate root.
-                            vec![tcx.crate_name(defid.krate)]
-                        } else {
-                            if fqp.len() < 2 {
-                                return None;
-                            }
-                            fqp[..fqp.len() - 1].to_vec()
-                        };
+                    let path = if item.ty == ItemType::Macro
+                        && find_attr!(tcx.get_all_attrs(defid), AttributeKind::MacroExport { .. })
+                    {
+                        // `#[macro_export]` always exports to the crate root.
+                        vec![tcx.crate_name(defid.krate)]
+                    } else {
+                        if fqp.len() < 2 {
+                            return None;
+                        }
+                        fqp[..fqp.len() - 1].to_vec()
+                    };
                     if path == item.module_path {
                         return None;
                     }
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 8bc2e0bd957..ef7ce33298d 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -2,11 +2,9 @@ use std::path::{Path, PathBuf};
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{
-    ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath,
-};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
+use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
@@ -67,7 +65,7 @@ struct SpanMapVisitor<'tcx> {
 
 impl SpanMapVisitor<'_> {
     /// This function is where we handle `hir::Path` elements and add them into the "span map".
-    fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
+    fn handle_path(&mut self, path: &rustc_hir::Path<'_>, only_use_last_segment: bool) {
         match path.res {
             // FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
             // Would be nice to support them too alongside the other `DefKind`
@@ -79,24 +77,36 @@ impl SpanMapVisitor<'_> {
                     LinkFromSrc::External(def_id)
                 };
                 // In case the path ends with generics, we remove them from the span.
-                let span = path
-                    .segments
-                    .last()
-                    .map(|last| {
-                        // In `use` statements, the included item is not in the path segments.
-                        // However, it doesn't matter because you can't have generics on `use`
-                        // statements.
-                        if path.span.contains(last.ident.span) {
-                            path.span.with_hi(last.ident.span.hi())
-                        } else {
-                            path.span
-                        }
-                    })
-                    .unwrap_or(path.span);
+                let span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.segments
+                        .last()
+                        .map(|last| {
+                            // In `use` statements, the included item is not in the path segments.
+                            // However, it doesn't matter because you can't have generics on `use`
+                            // statements.
+                            if path.span.contains(last.ident.span) {
+                                path.span.with_hi(last.ident.span.hi())
+                            } else {
+                                path.span
+                            }
+                        })
+                        .unwrap_or(path.span)
+                };
                 self.matches.insert(span, link);
             }
             Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => {
-                self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
+                let path_span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.span
+                };
+                self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span)));
             }
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
@@ -189,31 +199,23 @@ impl SpanMapVisitor<'_> {
             self.matches.insert(span, link);
         }
     }
+}
 
-    fn handle_pat(&mut self, p: &Pat<'_>) {
-        let mut check_qpath = |qpath, hir_id| match qpath {
-            QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
-                self.infer_id(path.hir_id, Some(hir_id), qpath.span());
-            }
-            QPath::Resolved(_, path) => self.handle_path(path),
-            _ => {}
-        };
-        match p.kind {
-            PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
-            PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => {
-                check_qpath(qpath, p.hir_id)
-            }
-            PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => {
-                check_qpath(*qpath, *hir_id)
-            }
-            PatKind::Or(pats) => {
-                for pat in pats {
-                    self.handle_pat(pat);
-                }
-            }
-            _ => {}
+// This is a reimplementation of `hir_enclosing_body_owner` which allows to fail without
+// panicking.
+fn hir_enclosing_body_owner(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<LocalDefId> {
+    for (_, node) in tcx.hir_parent_iter(hir_id) {
+        // FIXME: associated type impl items don't have an associated body, so we don't handle
+        // them currently.
+        if let Node::ImplItem(impl_item) = node
+            && matches!(impl_item.kind, rustc_hir::ImplItemKind::Type(_))
+        {
+            return None;
+        } else if let Some((def_id, _)) = node.associated_body() {
+            return Some(def_id);
         }
     }
+    None
 }
 
 impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
@@ -227,12 +229,42 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         if self.handle_macro(path.span) {
             return;
         }
-        self.handle_path(path);
+        self.handle_path(path, false);
         intravisit::walk_path(self, path);
     }
 
-    fn visit_pat(&mut self, p: &Pat<'tcx>) {
-        self.handle_pat(p);
+    fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) {
+        match *qpath {
+            QPath::TypeRelative(qself, path) => {
+                if matches!(path.res, Res::Err) {
+                    let tcx = self.tcx;
+                    if let Some(body_id) = hir_enclosing_body_owner(tcx, id) {
+                        let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id());
+                        let path = rustc_hir::Path {
+                            // We change the span to not include parens.
+                            span: path.ident.span,
+                            res: typeck_results.qpath_res(qpath, id),
+                            segments: &[],
+                        };
+                        self.handle_path(&path, false);
+                    }
+                } else {
+                    self.infer_id(path.hir_id, Some(id), path.ident.span);
+                }
+
+                rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself));
+                self.visit_path_segment(path);
+            }
+            QPath::Resolved(maybe_qself, path) => {
+                self.handle_path(path, true);
+
+                rustc_ast::visit::visit_opt!(self, visit_ty_unambig, maybe_qself);
+                if !self.handle_macro(path.span) {
+                    intravisit::walk_path(self, path);
+                }
+            }
+            _ => {}
+        }
     }
 
     fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index e37a5246a76..3a1db805d01 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -386,8 +386,13 @@ impl CratesIndexPart {
         let layout = &cx.shared.layout;
         let style_files = &cx.shared.style_files;
         const DELIMITER: &str = "\u{FFFC}"; // users are being naughty if they have this
-        let content =
-            format!("<h1>List of all crates</h1><ul class=\"all-items\">{DELIMITER}</ul>");
+        let content = format!(
+            "<div class=\"main-heading\">\
+                <h1>List of all crates</h1>\
+                <rustdoc-toolbar></rustdoc-toolbar>\
+            </div>\
+            <ul class=\"all-items\">{DELIMITER}</ul>"
+        );
         let template = layout::render(layout, &page, "", content, style_files);
         SortedTemplate::from_template(&template, DELIMITER)
             .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page")
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 75febd6f737..3ea9de381ec 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -2227,11 +2227,18 @@ function preLoadCss(cssUrl) {
     });
 }());
 
-// This section is a bugfix for firefox: when copying text with `user-select: none`, it adds
-// extra backline characters.
+
+// Workaround for browser-specific bugs when copying code snippets.
+//
+// * In Firefox, copying text that includes elements with `user-select: none`
+//   inserts extra blank lines.
+//   - Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836
+//   - Rust issue: https://github.com/rust-lang/rust/issues/141464
 //
-// Rustdoc issue: Workaround for https://github.com/rust-lang/rust/issues/141464
-// Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836
+// * In Chromium-based browsers, `document.getSelection()` includes elements
+//   with `user-select: none`, causing unwanted line numbers to be copied.
+//   - Chromium issue: https://issues.chromium.org/issues/446539520
+//   - Rust issue: https://github.com/rust-lang/rust/issues/146816
 (function() {
     document.body.addEventListener("copy", event => {
         let target = nonnull(event.target);
@@ -2248,9 +2255,13 @@ function preLoadCss(cssUrl) {
         if (!isInsideCode) {
             return;
         }
-        const selection = document.getSelection();
-         // @ts-expect-error
-        nonnull(event.clipboardData).setData("text/plain", selection.toString());
+        const selection = nonnull(document.getSelection());
+        const text = Array.from({ length: selection.rangeCount }, (_, i) => {
+            const fragment = selection.getRangeAt(i).cloneContents();
+            fragment.querySelectorAll("[data-nosnippet]").forEach(el => el.remove());
+            return fragment.textContent;
+        }).join("");
+        nonnull(event.clipboardData).setData("text/plain", text);
         event.preventDefault();
     });
 }());
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 0034552bdd3..49153d58fe9 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -65,5 +65,10 @@
             <strong>Note:</strong> Encountered an error during type layout; {#+ #}
             the type's layout depended on the type's layout itself. {# #}
         </p>
+        {% when Err(LayoutError::InvalidSimd {..}) %}
+        <p> {# #}
+            <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+            the vector type had zero elements or too many elements. {# #}
+        </p>
         {% endmatch %}
 </div> {# #}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 6fe94f9d291..779e26c7b0f 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -912,12 +912,8 @@ fn maybe_from_hir_attr(
         hir::Attribute::Parsed(kind) => kind,
 
         hir::Attribute::Unparsed(_) => {
-            return Some(if attr.has_name(sym::macro_export) {
-                Attribute::MacroExport
-                // FIXME: We should handle `#[doc(hidden)]`.
-            } else {
-                other_attr(tcx, attr)
-            });
+            // FIXME: We should handle `#[doc(hidden)]`.
+            return Some(other_attr(tcx, attr));
         }
     };
 
@@ -925,6 +921,7 @@ fn maybe_from_hir_attr(
         AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation.
         AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"),
 
+        AK::MacroExport { .. } => Attribute::MacroExport,
         AK::MustUse { reason, span: _ } => {
             Attribute::MustUse { reason: reason.map(|s| s.to_string()) }
         }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 9871066b9eb..5d8f8f4bed1 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -10,6 +10,7 @@
 #![feature(box_patterns)]
 #![feature(debug_closure_helpers)]
 #![feature(file_buffered)]
+#![feature(formatting_options)]
 #![feature(if_let_guard)]
 #![feature(iter_advance_by)]
 #![feature(iter_intersperse)]
@@ -835,8 +836,10 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
         config::InputMode::NoInputMergeFinalize => {
             return wrap_return(
                 dcx,
-                run_merge_finalize(render_options)
-                    .map_err(|e| format!("could not write merged cross-crate info: {e}")),
+                rustc_span::create_session_globals_then(options.edition, &[], None, || {
+                    run_merge_finalize(render_options)
+                        .map_err(|e| format!("could not write merged cross-crate info: {e}"))
+                }),
             );
         }
     };
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index da09117b1bb..136ff258048 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -364,6 +364,7 @@ impl TagParser {
             } else {
                 if !self.tag_name.is_empty() {
                     self.in_attrs = true;
+                    // range of the entire tag within dox
                     let mut r = Range { start: range.start + start_pos, end: range.start + pos };
                     if c == '>' {
                         // In case we have a tag without attribute, we can consider the span to
@@ -381,7 +382,7 @@ impl TagParser {
                             for (new_pos, c) in text[pos..].char_indices() {
                                 if !c.is_whitespace() {
                                     if c == '>' {
-                                        r.end = range.start + new_pos + 1;
+                                        r.end = range.start + pos + new_pos + 1;
                                         found = true;
                                     } else if c == '<' {
                                         self.handle_lt_in_tag(range.clone(), pos + new_pos, f);
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 3388ae46f05..525d05b6a98 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -2,9 +2,10 @@
 
 use std::mem;
 
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
+use rustc_hir::find_attr;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
 use tracing::debug;
 
 use crate::clean::utils::inherits_doc_hidden;
@@ -114,7 +115,7 @@ impl DocFolder for Stripper<'_, '_> {
             // If the macro has the `#[macro_export]` attribute, it means it's accessible at the
             // crate level so it should be handled differently.
             clean::MacroItem(..) => {
-                i.attrs.other_attrs.iter().any(|attr| attr.has_name(sym::macro_export))
+                find_attr!(&i.attrs.other_attrs, AttributeKind::MacroExport { .. })
             }
             _ => false,
         };
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b2e4b594375..cd28322f590 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -5,10 +5,11 @@ use std::mem;
 
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir as hir;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, MacroKinds, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
 use rustc_hir::intravisit::{Visitor, walk_body, walk_item};
-use rustc_hir::{CRATE_HIR_ID, Node};
+use rustc_hir::{CRATE_HIR_ID, Node, find_attr};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -166,7 +167,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             if !child.reexport_chain.is_empty()
                 && let Res::Def(DefKind::Macro(_), def_id) = child.res
                 && let Some(local_def_id) = def_id.as_local()
-                && self.cx.tcx.has_attr(def_id, sym::macro_export)
+                && find_attr!(self.cx.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. })
                 && inserted.insert(def_id)
             {
                 let item = self.cx.tcx.hir_expect_item(local_def_id);
@@ -406,7 +407,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             || match item.kind {
                 hir::ItemKind::Impl(..) => true,
                 hir::ItemKind::Macro(_, _, _) => {
-                    self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export)
+                    find_attr!(self.cx.tcx.get_all_attrs(item.owner_id.def_id), AttributeKind::MacroExport{..})
                 }
                 _ => false,
             }
@@ -524,7 +525,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
                 let def_id = item.owner_id.to_def_id();
                 let is_macro_2_0 = !macro_def.macro_rules;
-                let nonexported = !tcx.has_attr(def_id, sym::macro_export);
+                let nonexported =
+                    !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. });
 
                 if is_macro_2_0 || nonexported || self.inlining {
                     self.add_to_current_mod(item, renamed, import_id);
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 333793696b0a08002acac6af983adc7a5233fc5
+Subproject 8c30b9c5098bdff1d3d9a2d460ee091cd1171e6
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 966f94733bbc94ca51ff9f1e4c49ad250ebbdc5
+Subproject f2932725b045d361ff5f18ba02b1409dd1f44e7
diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
index 9071c9c95f9..c5acaf09993 100644
--- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -5,10 +5,12 @@ use itertools::Itertools;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource};
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::find_attr;
 use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
 use rustc_middle::lint::LevelAndSource;
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, SyntaxContext, sym};
+use rustc_span::{Span, SyntaxContext};
 use std::collections::BTreeMap;
 use std::collections::btree_map::Entry;
 
@@ -146,7 +148,8 @@ struct BodyVisitor<'a, 'tcx> {
 }
 
 fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
-    (cx.effective_visibilities.is_exported(def_id) || cx.tcx.has_attr(def_id, sym::macro_export))
+    ( cx.effective_visibilities.is_exported(def_id) ||
+        find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::MacroExport{..}) )
         && !cx.tcx.is_doc_hidden(def_id)
 }
 
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
index 49595e2fec2..786c61e0c01 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
@@ -10,34 +10,42 @@ if let StmtKind::Let(local) = stmt.kind
     && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
     && let ExprKind::Block(block1, None) = args[0].kind
-    && block1.stmts.len() == 1
+    && block1.stmts.len() == 2
     && let StmtKind::Let(local1) = block1.stmts[0].kind
     && let Some(init1) = local1.init
-    && let ExprKind::Array(elements) = init1.kind
+    && let ExprKind::Tup(elements) = init1.kind
     && elements.len() == 1
-    && let ExprKind::Call(func1, args1) = elements[0].kind
-    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
-    && args1.len() == 1
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = elements[0].kind
     && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind
     && name.as_str() == "args"
+    && let StmtKind::Let(local2) = block1.stmts[1].kind
+    && let Some(init2) = local2.init
+    && let ExprKind::Array(elements1) = init2.kind
+    && elements1.len() == 1
+    && let ExprKind::Call(func1, args1) = elements1[0].kind
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
+    && args1.len() == 1
+    && let ExprKind::Field(object, field_name) = args1[0].kind
+    && field_name.as_str() == "0"
+    && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local2.pat.kind
+    && name1.as_str() == "args"
     && let Some(trailing_expr) = block1.expr
     && let ExprKind::Call(func2, args2) = trailing_expr.kind
     && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
     && args2.len() == 2
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
-    && let ExprKind::Array(elements1) = inner1.kind
-    && elements1.len() == 2
-    && let ExprKind::Lit(ref lit) = elements1[0].kind
+    && let ExprKind::Array(elements2) = inner1.kind
+    && elements2.len() == 2
+    && let ExprKind::Lit(ref lit) = elements2[0].kind
     && let LitKind::Str(s, _) = lit.node
     && s.as_str() == ""
-    && let ExprKind::Lit(ref lit1) = elements1[1].kind
+    && let ExprKind::Lit(ref lit1) = elements2[1].kind
     && let LitKind::Str(s1, _) = lit1.node
     && s1.as_str() == "\n"
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
     && block.expr.is_none()
-    && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
-    && name1.as_str() == "print_text"
+    && let PatKind::Binding(BindingMode::NONE, _, name2, None) = local.pat.kind
+    && name2.as_str() == "print_text"
 {
     // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
index 4fc7b49464d..80717900b52 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
@@ -20,28 +20,36 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
     && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
     && args.len() == 1
     && let ExprKind::Block(block2, None) = args[0].kind
-    && block2.stmts.len() == 1
+    && block2.stmts.len() == 2
     && let StmtKind::Let(local) = block2.stmts[0].kind
     && let Some(init) = local.init
-    && let ExprKind::Array(elements) = init.kind
+    && let ExprKind::Tup(elements) = init.kind
     && elements.len() == 1
-    && let ExprKind::Call(func1, args1) = elements[0].kind
-    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
-    && args1.len() == 1
-    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = elements[0].kind
     && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
     && name1.as_str() == "args"
+    && let StmtKind::Let(local1) = block2.stmts[1].kind
+    && let Some(init1) = local1.init
+    && let ExprKind::Array(elements1) = init1.kind
+    && elements1.len() == 1
+    && let ExprKind::Call(func1, args1) = elements1[0].kind
+    && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
+    && args1.len() == 1
+    && let ExprKind::Field(object, field_name) = args1[0].kind
+    && field_name.as_str() == "0"
+    && let PatKind::Binding(BindingMode::NONE, _, name2, None) = local1.pat.kind
+    && name2.as_str() == "args"
     && let Some(trailing_expr) = block2.expr
     && let ExprKind::Call(func2, args2) = trailing_expr.kind
     && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
     && args2.len() == 2
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
-    && let ExprKind::Array(elements1) = inner1.kind
-    && elements1.len() == 2
-    && let ExprKind::Lit(ref lit2) = elements1[0].kind
+    && let ExprKind::Array(elements2) = inner1.kind
+    && elements2.len() == 2
+    && let ExprKind::Lit(ref lit2) = elements2[0].kind
     && let LitKind::Str(s, _) = lit2.node
     && s.as_str() == ""
-    && let ExprKind::Lit(ref lit3) = elements1[1].kind
+    && let ExprKind::Lit(ref lit3) = elements2[1].kind
     && let LitKind::Str(s1, _) = lit3.node
     && s1.as_str() == "\n"
     && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
index 15070dd9c2c..e0bc23e0788 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.fixed
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -153,7 +153,7 @@ pub mod redundant_imports_issue {
         () => {};
     }
 
-    #[expect(redundant_imports)]
+    #[expect(unused_imports)]
     pub(crate) use empty;
 
     empty!();
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
index 3f530de7fd8..30a4c354b23 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.rs
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -153,7 +153,7 @@ pub mod redundant_imports_issue {
         () => {};
     }
 
-    #[expect(redundant_imports)]
+    #[expect(unused_imports)]
     pub(crate) use empty;
 
     empty!();
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index cdada5a2230..6597c3c70f6 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -12,7 +12,7 @@ path = "src/bin/main.rs"
 
 [dependencies]
 # tidy-alphabetical-start
-anstyle-svg = "0.1.3"
+anstyle-svg = "0.1.11"
 build_helper = { path = "../../build_helper" }
 camino = "1"
 colored = "2"
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 1277fd225eb..e84a2278766 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -201,6 +201,8 @@ pub struct TestProps {
     /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios
     /// that don't otherwise want/need `-Z build-std`.
     pub add_core_stubs: bool,
+    /// Add these flags to the build of `minicore`.
+    pub core_stubs_compile_flags: Vec<String>,
     /// Whether line annotatins are required for the given error kind.
     pub dont_require_annotations: HashSet<ErrorKind>,
     /// Whether pretty printers should be disabled in gdb.
@@ -253,6 +255,7 @@ mod directives {
     pub const FILECHECK_FLAGS: &'static str = "filecheck-flags";
     pub const NO_AUTO_CHECK_CFG: &'static str = "no-auto-check-cfg";
     pub const ADD_CORE_STUBS: &'static str = "add-core-stubs";
+    pub const CORE_STUBS_COMPILE_FLAGS: &'static str = "core-stubs-compile-flags";
     // This isn't a real directive, just one that is probably mistyped often
     pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
     pub const DISABLE_GDB_PRETTY_PRINTERS: &'static str = "disable-gdb-pretty-printers";
@@ -311,6 +314,7 @@ impl TestProps {
             no_auto_check_cfg: false,
             has_enzyme: false,
             add_core_stubs: false,
+            core_stubs_compile_flags: vec![],
             dont_require_annotations: Default::default(),
             disable_gdb_pretty_printers: false,
             compare_output_by_lines: false,
@@ -653,6 +657,21 @@ impl TestProps {
 
                     self.update_add_core_stubs(ln, config);
 
+                    if let Some(flags) = config.parse_name_value_directive(
+                        ln,
+                        directives::CORE_STUBS_COMPILE_FLAGS,
+                        testfile,
+                        line_number,
+                    ) {
+                        let flags = split_flags(&flags);
+                        for flag in &flags {
+                            if flag == "--edition" || flag.starts_with("--edition=") {
+                                panic!("you must use `//@ edition` to configure the edition");
+                            }
+                        }
+                        self.core_stubs_compile_flags.extend(flags);
+                    }
+
                     if let Some(err_kind) = config.parse_name_value_directive(
                         ln,
                         DONT_REQUIRE_ANNOTATIONS,
diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs
index 0ef84fb4594..4fef8992567 100644
--- a/src/tools/compiletest/src/directives/directive_names.rs
+++ b/src/tools/compiletest/src/directives/directive_names.rs
@@ -19,6 +19,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "check-test-line-numbers-match",
     "compare-output-by-lines",
     "compile-flags",
+    "core-stubs-compile-flags",
     "disable-gdb-pretty-printers",
     "doc-flags",
     "dont-check-compiler-stderr",
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 89fb8eb4357..bd32bec383f 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1322,6 +1322,7 @@ impl<'test> TestCx<'test> {
 
         rustc.args(&["--crate-type", "rlib"]);
         rustc.arg("-Cpanic=abort");
+        rustc.args(self.props.core_stubs_compile_flags.clone());
 
         let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None);
         if !res.status.success() {
@@ -1432,6 +1433,12 @@ impl<'test> TestCx<'test> {
 
         aux_rustc.arg("-L").arg(&aux_dir);
 
+        if aux_props.add_core_stubs {
+            let minicore_path = self.build_minicore();
+            aux_rustc.arg("--extern");
+            aux_rustc.arg(&format!("minicore={}", minicore_path));
+        }
+
         let auxres = aux_cx.compose_and_run(
             aux_rustc,
             aux_cx.config.compile_lib_path.as_path(),
@@ -1858,14 +1865,13 @@ impl<'test> TestCx<'test> {
             }
         }
 
-        rustc.args(&self.props.compile_flags);
-
         // FIXME(jieyouxu): we should report a fatal error or warning if user wrote `-Cpanic=` with
-        // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`,
-        // however, by moving this last we should override previous `-Cpanic`s and
-        // `-Cforce-unwind-tables`s. Note that checking here is very fragile, because we'd have to
-        // account for all possible compile flag splittings (they have some... intricacies and are
-        // not yet normalized).
+        // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`.
+        //
+        // We could apply these last and override any provided flags. That would ensure that the
+        // build works, but some tests want to exercise that mixing panic modes in specific ways is
+        // rejected. So we enable aborting panics and unwind tables before adding flags, just to
+        // change the default.
         //
         // `minicore` requires `#![no_std]` and `#![no_core]`, which means no unwinding panics.
         if self.props.add_core_stubs {
@@ -1873,6 +1879,8 @@ impl<'test> TestCx<'test> {
             rustc.arg("-Cforce-unwind-tables=yes");
         }
 
+        rustc.args(&self.props.compile_flags);
+
         rustc
     }
 
@@ -2655,7 +2663,7 @@ impl<'test> TestCx<'test> {
 
             // The alloc-id appears in pretty-printed allocations.
             normalized = static_regex!(
-                r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼"
+                r"╾─*a(lloc)?([0-9]+)(\+0x[0-9a-f]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼"
             )
             .replace_all(&normalized, |caps: &Captures<'_>| {
                 // Renumber the captured index.
diff --git a/src/tools/features-status-dump/src/main.rs b/src/tools/features-status-dump/src/main.rs
index 1ce98d1506d..a4f88362ab8 100644
--- a/src/tools/features-status-dump/src/main.rs
+++ b/src/tools/features-status-dump/src/main.rs
@@ -5,6 +5,7 @@ use std::path::PathBuf;
 
 use anyhow::{Context, Result};
 use clap::Parser;
+use tidy::diagnostics::RunningCheck;
 use tidy::features::{Feature, collect_lang_features, collect_lib_features};
 
 #[derive(Debug, Parser)]
@@ -29,7 +30,7 @@ struct FeaturesStatus {
 fn main() -> Result<()> {
     let Cli { compiler_path, library_path, output_path } = Cli::parse();
 
-    let lang_features_status = collect_lang_features(&compiler_path, &mut false);
+    let lang_features_status = collect_lang_features(&compiler_path, &mut RunningCheck::new_noop());
     let lib_features_status = collect_lib_features(&library_path)
         .into_iter()
         .filter(|&(ref name, _)| !lang_features_status.contains_key(name))
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index e1a948c92fa..740118bb4a0 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -117,6 +117,41 @@ jobs:
       - name: rustdoc
         run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items
 
+  bootstrap:
+    name: bootstrap build
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      # Deliberately skipping `./.github/workflows/setup` as we do our own setup
+      - name: Add cache for cargo
+        id: cache
+        uses: actions/cache@v4
+        with:
+          path: |
+            # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>.
+            # Cache package/registry information
+            ~/.cargo/registry/index
+            ~/.cargo/registry/cache
+            ~/.cargo/git/db
+            # Cache bootstrap downloads
+            ../rust/build/cache
+          key: cargo-bootstrap-${{ hashFiles('rust-version') }}
+          restore-keys: cargo-bootstrap
+      - name: prepare build environment
+        run: |
+          MIRIDIR=$(pwd)
+          cd ..
+          # Bootstrap needs at least depth 2 to function.
+          git clone https://github.com/rust-lang/rust/ rust --depth 2 --revision $(cat "$MIRIDIR/rust-version")
+          cd rust
+          # Replace the in-tree Miri with the current version.
+          rm src/tools/miri -rf
+          ln -s "$MIRIDIR" src/tools/miri
+      - name: check build
+        run: |
+          cd ../rust # ./x does not seem to like being invoked from elsewhere
+          ./x check miri
+
   coverage:
     name: coverage report
     runs-on: ubuntu-latest
@@ -130,7 +165,7 @@ jobs:
   # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
   # And they should be added below in `cron-fail-notify` as well.
   conclusion:
-    needs: [test, style, coverage]
+    needs: [test, style, bootstrap, coverage]
     # We need to ensure this job does *not* get skipped if its dependencies fail,
     # because a skipped job is considered a success by GitHub. So we have to
     # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
@@ -211,7 +246,7 @@ jobs:
   cron-fail-notify:
     name: cronjob failure notification
     runs-on: ubuntu-latest
-    needs: [test, style, coverage]
+    needs: [test, style, bootstrap, coverage]
     if: ${{ github.event_name == 'schedule' && failure() }}
     steps:
       # Send a Zulip notification
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index ee09b9b4b73..f1b52293123 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -130,15 +130,15 @@ impl Command {
         let new_commit = sh.read_file("rust-version")?.trim().to_owned();
         let current_commit = {
             let rustc_info = cmd!(sh, "rustc +miri --version -v").read();
-            if rustc_info.is_err() {
-                None
-            } else {
-                let metadata = rustc_version::version_meta_for(&rustc_info.unwrap())?;
+            if let Ok(rustc_info) = rustc_info {
+                let metadata = rustc_version::version_meta_for(&rustc_info)?;
                 Some(
                     metadata
                         .commit_hash
                         .ok_or_else(|| anyhow!("rustc metadata did not contain commit hash"))?,
                 )
+            } else {
+                None
             }
         };
         // Check if we already are at that commit.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 0eb16a943d6..388e88fe43e 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-3f1552a273e43e15f6ed240d00e1efdd6a53e65e
+f6092f224d2b1774b31033f12d0bee626943b02f
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index 7b4c533cfae..00f921b0f8a 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -244,8 +244,8 @@ pub(super) enum TransitionError {
     ChildAccessForbidden(Permission),
     /// A protector was triggered due to an invalid transition that loses
     /// too much permissions.
-    /// For example, if a protected tag goes from `Active` to `Disabled` due
-    /// to a foreign write this will produce a `ProtectedDisabled(Active)`.
+    /// For example, if a protected tag goes from `Unique` to `Disabled` due
+    /// to a foreign write this will produce a `ProtectedDisabled(Unique)`.
     /// This kind of error can only occur on foreign accesses.
     ProtectedDisabled(Permission),
     /// Cannot deallocate because some tag in the allocation is strongly protected.
@@ -504,7 +504,7 @@ impl DisplayFmt {
         if let Some(perm) = perm {
             format!(
                 "{ac}{st}",
-                ac = if perm.is_accessed() { self.accessed.yes } else { self.accessed.no },
+                ac = if perm.accessed() { self.accessed.yes } else { self.accessed.no },
                 st = perm.permission().short_name(),
             )
         } else {
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs
index 928b3e6baef..90df05d36d9 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/foreign_access_skipping.rs
@@ -24,7 +24,7 @@ use super::tree::AccessRelatedness;
 /// "manually" reset the parent's SIFA to be at least as strong as the new child's. This is accomplished with the `ensure_no_stronger_than` method.
 ///
 /// Note that we derive Ord and PartialOrd, so the order in which variants are listed below matters:
-/// None < Read < Write. Do not change that order. See the `test_order` test.
+/// None < Read < Write (weaker to stronger). Do not change that order. See the `test_order` test.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
 pub enum IdempotentForeignAccess {
     #[default]
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index bed65440dc9..6e5b5c807aa 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -294,24 +294,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
         }
 
-        let span = this.machine.current_span();
-
-        // When adding a new node, the SIFA of its parents needs to be updated, potentially across
-        // the entire memory range. For the parts that are being accessed below, the access itself
-        // trivially takes care of that. However, we have to do some more work to also deal with the
-        // parts that are not being accessed. Specifically what we do is that we call
-        // `update_last_accessed_after_retag` on the SIFA of the permission set for the part of
-        // memory outside `perm_map` -- so that part is definitely taken care of. The remaining
-        // concern is the part of memory that is in the range of `perms_map`, but not accessed
-        // below. There we have two cases:
-        // * If the type is `!Freeze`, then the non-accessed part uses `nonfreeze_perm`, so the
-        //   `nonfreeze_perm` initialized parts are also fine. We enforce the `freeze_perm` parts to
-        //   be accessed via the assert below, and thus everything is taken care of.
-        // * If the type is `Freeze`, then `freeze_perm` is used everywhere (both inside and outside
-        //   the initial range), and we update everything to have the `freeze_perm`'s SIFA, so there
-        //   are no issues. (And this assert below is not actually needed in this case).
-        assert!(new_perm.freeze_access);
-
         let protected = new_perm.protector.is_some();
         let precise_interior_mut = this
             .machine
@@ -337,7 +319,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 LocationState::new_non_accessed(perm, sifa)
             }
         };
-        let perms_map = if !precise_interior_mut {
+        let inside_perms = if !precise_interior_mut {
             // For `!Freeze` types, just pretend the entire thing is an `UnsafeCell`.
             let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env());
             let state = loc_state(ty_is_freeze);
@@ -364,8 +346,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let alloc_extra = this.get_alloc_extra(alloc_id)?;
         let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
 
-        for (perm_range, perm) in perms_map.iter_all() {
-            if perm.is_accessed() {
+        for (perm_range, perm) in inside_perms.iter_all() {
+            if perm.accessed() {
                 // Some reborrows incur a read access to the parent.
                 // Adjust range to be relative to allocation start (rather than to `place`).
                 let range_in_alloc = AllocRange {
@@ -401,10 +383,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             base_offset,
             orig_tag,
             new_tag,
-            perms_map,
+            inside_perms,
             new_perm.outside_perm,
             protected,
-            span,
+            this.machine.current_span(),
         )?;
         drop(tree_borrows);
 
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index 390435e58d1..e21775c9f23 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -14,7 +14,7 @@ enum PermissionPriv {
     Cell,
     /// represents: a local mutable reference that has not yet been written to;
     /// allows: child reads, foreign reads;
-    /// affected by: child writes (becomes Active),
+    /// affected by: child writes (becomes Unique),
     /// rejects: foreign writes (Disabled).
     ///
     /// `ReservedFrz` is mostly for types that are `Freeze` (no interior mutability).
@@ -31,17 +31,17 @@ enum PermissionPriv {
     /// This is so that the behavior of `Reserved` adheres to the rules of `noalias`:
     /// - foreign-read then child-write is UB due to `conflicted`,
     /// - child-write then foreign-read is UB since child-write will activate and then
-    ///   foreign-read disables a protected `Active`, which is UB.
+    ///   foreign-read disables a protected `Unique`, which is UB.
     ReservedFrz { conflicted: bool },
     /// Alternative version of `ReservedFrz` made for types with interior mutability.
     /// allows: child reads, foreign reads, foreign writes (extra);
-    /// affected by: child writes (becomes Active);
+    /// affected by: child writes (becomes Unique);
     /// rejects: nothing.
     ReservedIM,
     /// represents: a unique pointer;
     /// allows: child reads, child writes;
     /// rejects: foreign reads (Frozen), foreign writes (Disabled).
-    Active,
+    Unique,
     /// represents: a shared pointer;
     /// allows: all read accesses;
     /// rejects child writes (UB), foreign writes (Disabled).
@@ -56,7 +56,7 @@ use super::foreign_access_skipping::IdempotentForeignAccess;
 
 impl PartialOrd for PermissionPriv {
     /// PermissionPriv is ordered by the reflexive transitive closure of
-    /// `Reserved(conflicted=false) < Reserved(conflicted=true) < Active < Frozen < Disabled`.
+    /// `Reserved(conflicted=false) < Reserved(conflicted=true) < Unique < Frozen < Disabled`.
     /// `Reserved` that have incompatible `ty_is_freeze` are incomparable to each other.
     /// This ordering matches the reachability by transitions, as asserted by the exhaustive test
     /// `permissionpriv_partialord_is_reachability`.
@@ -76,8 +76,8 @@ impl PartialOrd for PermissionPriv {
             (_, Disabled) => Less,
             (Frozen, _) => Greater,
             (_, Frozen) => Less,
-            (Active, _) => Greater,
-            (_, Active) => Less,
+            (Unique, _) => Greater,
+            (_, Unique) => Less,
             (ReservedIM, ReservedIM) => Equal,
             (ReservedFrz { conflicted: c1 }, ReservedFrz { conflicted: c2 }) => {
                 // `bool` is ordered such that `false <= true`, so this works as intended.
@@ -115,8 +115,8 @@ impl PermissionPriv {
             // Famously, ReservedIM survives foreign writes. It is never protected.
             ReservedIM if prot => unreachable!("Protected ReservedIM should not exist!"),
             ReservedIM => IdempotentForeignAccess::Write,
-            // Active changes on any foreign access (becomes Frozen/Disabled).
-            Active => IdempotentForeignAccess::None,
+            // Unique changes on any foreign access (becomes Frozen/Disabled).
+            Unique => IdempotentForeignAccess::None,
             // Frozen survives foreign reads, but not writes.
             Frozen => IdempotentForeignAccess::Read,
             // Disabled survives foreign reads and writes. It survives them
@@ -139,12 +139,12 @@ mod transition {
             Disabled => return None,
             // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read
             // accesses, since the data is not being mutated. Hence the `{ .. }`.
-            readable @ (Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable,
+            readable @ (Cell | ReservedFrz { .. } | ReservedIM | Unique | Frozen) => readable,
         })
     }
 
     /// A non-child node was read-accessed: keep `Reserved` but mark it as `conflicted` if it
-    /// is protected; invalidate `Active`.
+    /// is protected; invalidate `Unique`.
     fn foreign_read(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
         Some(match state {
             // Cell ignores foreign reads.
@@ -167,10 +167,10 @@ mod transition {
                 assert!(!protected);
                 res
             }
-            Active =>
+            Unique =>
                 if protected {
                     // We wrote, someone else reads -- that's bad.
-                    // (Since Active is always initialized, this move-to-protected will mean insta-UB.)
+                    // (Since Unique is always initialized, this move-to-protected will mean insta-UB.)
                     Disabled
                 } else {
                     // We don't want to disable here to allow read-read reordering: it is crucial
@@ -180,7 +180,7 @@ mod transition {
         })
     }
 
-    /// A child node was write-accessed: `Reserved` must become `Active` to obtain
+    /// A child node was write-accessed: `Reserved` must become `Unique` to obtain
     /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB.
     fn child_write(state: PermissionPriv, protected: bool) -> Option<PermissionPriv> {
         Some(match state {
@@ -192,7 +192,7 @@ mod transition {
             ReservedFrz { conflicted: true } if protected => return None,
             // A write always activates the 2-phase borrow, even with interior
             // mutability
-            ReservedFrz { .. } | ReservedIM | Active => Active,
+            ReservedFrz { .. } | ReservedIM | Unique => Unique,
             Frozen | Disabled => return None,
         })
     }
@@ -266,8 +266,8 @@ impl Permission {
 
     /// Default initial permission of the root of a new tree at inbounds positions.
     /// Must *only* be used for the root, this is not in general an "initial" permission!
-    pub fn new_active() -> Self {
-        Self { inner: Active }
+    pub fn new_unique() -> Self {
+        Self { inner: Unique }
     }
 
     /// Default initial permission of a reborrowed mutable reference that is either
@@ -309,7 +309,7 @@ impl Permission {
             // Do not do perform access if it is a `Cell`, as this
             // can cause data races when using thread-safe data types.
             Cell => None,
-            Active => Some(AccessKind::Write),
+            Unique => Some(AccessKind::Write),
             _ => Some(AccessKind::Read),
         }
     }
@@ -344,7 +344,7 @@ impl Permission {
             (_, Cell) => false,
             // ReservedIM can be replaced by anything besides Cell.
             // ReservedIM allows all transitions, but unlike Cell, a local write
-            // to ReservedIM transitions to Active, while it is a no-op for Cell.
+            // to ReservedIM transitions to Unique, while it is a no-op for Cell.
             (ReservedIM, _) => true,
             (_, ReservedIM) => false,
             // Reserved (as parent, where conflictedness does not matter)
@@ -352,12 +352,12 @@ impl Permission {
             // since ReservedIM and Cell alone would survive foreign writes
             (ReservedFrz { .. }, _) => true,
             (_, ReservedFrz { .. }) => false,
-            // Active can not be replaced by something surviving
+            // Unique can not be replaced by something surviving
             // foreign reads and then remaining writable (i.e., Reserved*).
             // Replacing a state by itself is always okay, even if the child state is protected.
-            // Active can be replaced by Frozen, since it is not protected.
-            (Active, Active | Frozen | Disabled) => true,
-            (_, Active) => false,
+            // Unique can be replaced by Frozen, since it is not protected.
+            (Unique, Unique | Frozen | Disabled) => true,
+            (_, Unique) => false,
             // Frozen can only be replaced by Disabled (and itself).
             (Frozen, Frozen | Disabled) => true,
             (_, Frozen) => false,
@@ -410,7 +410,7 @@ pub mod diagnostics {
                     ReservedFrz { conflicted: false } => "Reserved",
                     ReservedFrz { conflicted: true } => "Reserved (conflicted)",
                     ReservedIM => "Reserved (interior mutable)",
-                    Active => "Active",
+                    Unique => "Unique",
                     Frozen => "Frozen",
                     Disabled => "Disabled",
                 }
@@ -441,7 +441,7 @@ pub mod diagnostics {
                 ReservedFrz { conflicted: false } => "Res ",
                 ReservedFrz { conflicted: true } => "ResC",
                 ReservedIM => "ReIM",
-                Active => "Act ",
+                Unique => "Act ",
                 Frozen => "Frz ",
                 Disabled => "Dis ",
             }
@@ -455,7 +455,7 @@ pub mod diagnostics {
             assert!(self.is_possible());
             assert!(!self.is_noop());
             match (self.from, self.to) {
-                (_, Active) => "the first write to a 2-phase borrowed mutable reference",
+                (_, Unique) => "the first write to a 2-phase borrowed mutable reference",
                 (_, Frozen) => "a loss of write permissions",
                 (ReservedFrz { conflicted: false }, ReservedFrz { conflicted: true }) =>
                     "a temporary loss of write permissions until function exit",
@@ -472,8 +472,8 @@ pub mod diagnostics {
         ///
         /// Irrelevant events:
         /// - modifications of write permissions when the error is related to read permissions
-        ///   (on failed reads and protected `Frozen -> Disabled`, ignore `Reserved -> Active`,
-        ///   `Reserved(conflicted=false) -> Reserved(conflicted=true)`, and `Active -> Frozen`)
+        ///   (on failed reads and protected `Frozen -> Disabled`, ignore `Reserved -> Unique`,
+        ///   `Reserved(conflicted=false) -> Reserved(conflicted=true)`, and `Unique -> Frozen`)
         /// - all transitions for attempts to deallocate strongly protected tags
         ///
         /// # Panics
@@ -481,10 +481,10 @@ pub mod diagnostics {
         /// This function assumes that its arguments apply to the same location
         /// and that they were obtained during a normal execution. It will panic otherwise.
         /// - all transitions involved in `self` and `err` should be increasing
-        ///   (Reserved < Active < Frozen < Disabled);
+        ///   (Reserved < Unique < Frozen < Disabled);
         /// - between `self` and `err` the permission should also be increasing,
         ///   so all permissions inside `err` should be greater than `self.1`;
-        /// - `Active`, `Reserved(conflicted=false)`, and `Cell` cannot cause an error
+        /// - `Unique`, `Reserved(conflicted=false)`, and `Cell` cannot cause an error
         ///   due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)`
         ///   of either of them;
         /// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected
@@ -500,11 +500,11 @@ pub mod diagnostics {
                 TransitionError::ChildAccessForbidden(insufficient) => {
                     // Show where the permission was gained then lost,
                     // but ignore unrelated permissions.
-                    // This eliminates transitions like `Active -> Frozen`
+                    // This eliminates transitions like `Unique -> Frozen`
                     // when the error is a failed `Read`.
                     match (self.to, insufficient.inner) {
                         (Frozen, Frozen) => true,
-                        (Active, Frozen) => true,
+                        (Unique, Frozen) => true,
                         (Disabled, Disabled) => true,
                         (
                             ReservedFrz { conflicted: true, .. },
@@ -512,14 +512,14 @@ pub mod diagnostics {
                         ) => true,
                         // A pointer being `Disabled` is a strictly stronger source of
                         // errors than it being `Frozen`. If we try to access a `Disabled`,
-                        // then where it became `Frozen` (or `Active` or `Reserved`) is the least
+                        // then where it became `Frozen` (or `Unique` or `Reserved`) is the least
                         // of our concerns for now.
-                        (ReservedFrz { conflicted: true } | Active | Frozen, Disabled) => false,
+                        (ReservedFrz { conflicted: true } | Unique | Frozen, Disabled) => false,
                         (ReservedFrz { conflicted: true }, Frozen) => false,
 
-                        // `Active`, `Reserved`, and `Cell` have all permissions, so a
-                        // `ChildAccessForbidden(Reserved | Active)` can never exist.
-                        (_, Active) | (_, ReservedFrz { conflicted: false }) | (_, Cell) =>
+                        // `Unique`, `Reserved`, and `Cell` have all permissions, so a
+                        // `ChildAccessForbidden(Reserved | Unique)` can never exist.
+                        (_, Unique) | (_, ReservedFrz { conflicted: false }) | (_, Cell) =>
                             unreachable!("this permission cannot cause an error"),
                         // No transition has `Reserved { conflicted: false }` or `ReservedIM`
                         // as its `.to` unless it's a noop. `Cell` cannot be in its `.to`
@@ -527,11 +527,11 @@ pub mod diagnostics {
                         (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) =>
                             unreachable!("self is a noop transition"),
                         // All transitions produced in normal executions (using `apply_access`)
-                        // change permissions in the order `Reserved -> Active -> Frozen -> Disabled`.
+                        // change permissions in the order `Reserved -> Unique -> Frozen -> Disabled`.
                         // We assume that the error was triggered on the same location that
                         // the transition `self` applies to, so permissions found must be increasing
                         // in the order `self.from < self.to <= insufficient.inner`
-                        (Active | Frozen | Disabled, ReservedFrz { .. } | ReservedIM)
+                        (Unique | Frozen | Disabled, ReservedFrz { .. } | ReservedIM)
                         | (Disabled, Frozen)
                         | (ReservedFrz { .. }, ReservedIM) =>
                             unreachable!("permissions between self and err must be increasing"),
@@ -540,29 +540,29 @@ pub mod diagnostics {
                 TransitionError::ProtectedDisabled(before_disabled) => {
                     // Show how we got to the starting point of the forbidden transition,
                     // but ignore what came before.
-                    // This eliminates transitions like `Reserved -> Active`
+                    // This eliminates transitions like `Reserved -> Unique`
                     // when the error is a `Frozen -> Disabled`.
                     match (self.to, before_disabled.inner) {
                         // We absolutely want to know where it was activated/frozen/marked
                         // conflicted.
-                        (Active, Active) => true,
+                        (Unique, Unique) => true,
                         (Frozen, Frozen) => true,
                         (
                             ReservedFrz { conflicted: true, .. },
                             ReservedFrz { conflicted: true, .. },
                         ) => true,
                         // If the error is a transition `Frozen -> Disabled`, then we don't really
-                        // care whether before that was `Reserved -> Active -> Frozen` or
+                        // care whether before that was `Reserved -> Unique -> Frozen` or
                         // `Frozen` directly.
                         // The error will only show either
                         // - created as Reserved { conflicted: false },
                         //   then Reserved { .. } -> Disabled is forbidden
                         // - created as Reserved { conflicted: false },
-                        //   then Active -> Disabled is forbidden
+                        //   then Unique -> Disabled is forbidden
                         // A potential `Reserved { conflicted: false }
                         //   -> Reserved { conflicted: true }` is inexistant or irrelevant,
-                        // and so is the `Reserved { conflicted: false } -> Active`
-                        (Active, Frozen) => false,
+                        // and so is the `Reserved { conflicted: false } -> Unique`
+                        (Unique, Frozen) => false,
                         (ReservedFrz { conflicted: true }, _) => false,
 
                         (_, Disabled) =>
@@ -575,12 +575,12 @@ pub mod diagnostics {
                         (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) =>
                             unreachable!("self is a noop transition"),
 
-                        // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`,
+                        // Permissions only evolve in the order `Reserved -> Unique -> Frozen -> Disabled`,
                         // so permissions found must be increasing in the order
                         // `self.from < self.to <= forbidden.from < forbidden.to`.
-                        (Disabled, Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen)
-                        | (Frozen, Cell | ReservedFrz { .. } | ReservedIM | Active)
-                        | (Active, Cell | ReservedFrz { .. } | ReservedIM) =>
+                        (Disabled, Cell | ReservedFrz { .. } | ReservedIM | Unique | Frozen)
+                        | (Frozen, Cell | ReservedFrz { .. } | ReservedIM | Unique)
+                        | (Unique, Cell | ReservedFrz { .. } | ReservedIM) =>
                             unreachable!("permissions between self and err must be increasing"),
                     }
                 }
@@ -617,7 +617,7 @@ mod propagation_optimization_checks {
     impl Exhaustive for PermissionPriv {
         fn exhaustive() -> Box<dyn Iterator<Item = Self>> {
             Box::new(
-                vec![Active, Frozen, Disabled, ReservedIM, Cell]
+                vec![Unique, Frozen, Disabled, ReservedIM, Cell]
                     .into_iter()
                     .chain(<bool>::exhaustive().map(|conflicted| ReservedFrz { conflicted })),
             )
@@ -730,7 +730,7 @@ mod propagation_optimization_checks {
 
     #[test]
     // Check that all transitions are consistent with the order on PermissionPriv,
-    // i.e. Reserved -> Active -> Frozen -> Disabled
+    // i.e. Reserved -> Unique -> Frozen -> Disabled
     fn permissionpriv_partialord_is_reachability() {
         let reach = {
             let mut reach = rustc_data_structures::fx::FxHashSet::default();
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index 22bd63bd6b6..c4345c63289 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -11,7 +11,7 @@
 //! - idempotency properties asserted in `perms.rs` (for optimizations)
 
 use std::ops::Range;
-use std::{fmt, mem};
+use std::{cmp, fmt, mem};
 
 use rustc_abi::Size;
 use rustc_data_structures::fx::FxHashSet;
@@ -57,7 +57,7 @@ pub(super) struct LocationState {
 impl LocationState {
     /// Constructs a new initial state. It has neither been accessed, nor been subjected
     /// to any foreign access yet.
-    /// The permission is not allowed to be `Active`.
+    /// The permission is not allowed to be `Unique`.
     /// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs`
     pub fn new_non_accessed(permission: Permission, sifa: IdempotentForeignAccess) -> Self {
         assert!(permission.is_initial() || permission.is_disabled());
@@ -73,23 +73,10 @@ impl LocationState {
 
     /// Check if the location has been accessed, i.e. if it has
     /// ever been accessed through a child pointer.
-    pub fn is_accessed(&self) -> bool {
+    pub fn accessed(&self) -> bool {
         self.accessed
     }
 
-    /// Check if the state can exist as the initial permission of a pointer.
-    ///
-    /// Do not confuse with `is_accessed`, the two are almost orthogonal
-    /// as apart from `Active` which is not initial and must be accessed,
-    /// any other permission can have an arbitrary combination of being
-    /// initial/accessed.
-    /// FIXME: when the corresponding `assert` in `tree_borrows/mod.rs` finally
-    /// passes and can be uncommented, remove this `#[allow(dead_code)]`.
-    #[cfg_attr(not(test), allow(dead_code))]
-    pub fn is_initial(&self) -> bool {
-        self.permission.is_initial()
-    }
-
     pub fn permission(&self) -> Permission {
         self.permission
     }
@@ -170,7 +157,7 @@ impl LocationState {
             }
             if self.permission.is_frozen() && access_kind == AccessKind::Read {
                 // A foreign read to a `Frozen` tag will have almost no observable effect.
-                // It's a theorem that `Frozen` nodes have no active children, so all children
+                // It's a theorem that `Frozen` nodes have no `Unique` children, so all children
                 // already survive foreign reads. Foreign reads in general have almost no
                 // effect, the only further thing they could do is make protected `Reserved`
                 // nodes become conflicted, i.e. make them reject child writes for the further
@@ -265,7 +252,7 @@ pub(super) struct Node {
     pub children: SmallVec<[UniIndex; 4]>,
     /// Either `Reserved`,  `Frozen`, or `Disabled`, it is the permission this tag will
     /// lazily be initialized to on the first access.
-    /// It is only ever `Disabled` for a tree root, since the root is initialized to `Active` by
+    /// It is only ever `Disabled` for a tree root, since the root is initialized to `Unique` by
     /// its own separate mechanism.
     default_initial_perm: Permission,
     /// The default initial (strongest) idempotent foreign access.
@@ -598,14 +585,14 @@ impl Tree {
         };
         let rperms = {
             let mut perms = UniValMap::default();
-            // We manually set it to `Active` on all in-bounds positions.
-            // We also ensure that it is accessed, so that no `Active` but
+            // We manually set it to `Unique` on all in-bounds positions.
+            // We also ensure that it is accessed, so that no `Unique` but
             // not yet accessed nodes exist. Essentially, we pretend there
-            // was a write that initialized these to `Active`.
+            // was a write that initialized these to `Unique`.
             perms.insert(
                 root_idx,
                 LocationState::new_accessed(
-                    Permission::new_active(),
+                    Permission::new_unique(),
                     IdempotentForeignAccess::None,
                 ),
             );
@@ -618,30 +605,26 @@ impl Tree {
 impl<'tcx> Tree {
     /// Insert a new tag in the tree.
     ///
-    /// `initial_perms` defines the initial permissions for the part of memory
-    /// that is already considered "initialized" immediately. The ranges in this
-    /// map are relative to `base_offset`.
-    /// `default_perm` defines the initial permission for the rest of the allocation.
-    ///
-    /// For all non-accessed locations in the RangeMap (those that haven't had an
-    /// implicit read), their SIFA must be weaker than or as weak as the SIFA of
-    /// `default_perm`.
+    /// `inside_perm` defines the initial permissions for a block of memory starting at
+    /// `base_offset`. These may nor may not be already marked as "accessed".
+    /// `outside_perm` defines the initial permission for the rest of the allocation.
+    /// These are definitely not "accessed".
     pub(super) fn new_child(
         &mut self,
         base_offset: Size,
         parent_tag: BorTag,
         new_tag: BorTag,
-        initial_perms: DedupRangeMap<LocationState>,
-        default_perm: Permission,
+        inside_perms: DedupRangeMap<LocationState>,
+        outside_perm: Permission,
         protected: bool,
         span: Span,
     ) -> InterpResult<'tcx> {
         let idx = self.tag_mapping.insert(new_tag);
         let parent_idx = self.tag_mapping.get(&parent_tag).unwrap();
-        assert!(default_perm.is_initial());
+        assert!(outside_perm.is_initial());
 
         let default_strongest_idempotent =
-            default_perm.strongest_idempotent_foreign_access(protected);
+            outside_perm.strongest_idempotent_foreign_access(protected);
         // Create the node
         self.nodes.insert(
             idx,
@@ -649,47 +632,57 @@ impl<'tcx> Tree {
                 tag: new_tag,
                 parent: Some(parent_idx),
                 children: SmallVec::default(),
-                default_initial_perm: default_perm,
+                default_initial_perm: outside_perm,
                 default_initial_idempotent_foreign_access: default_strongest_idempotent,
-                debug_info: NodeDebugInfo::new(new_tag, default_perm, span),
+                debug_info: NodeDebugInfo::new(new_tag, outside_perm, span),
             },
         );
         // Register new_tag as a child of parent_tag
         self.nodes.get_mut(parent_idx).unwrap().children.push(idx);
 
+        // We need to know the weakest SIFA for `update_idempotent_foreign_access_after_retag`.
+        let mut min_sifa = default_strongest_idempotent;
         for (Range { start, end }, &perm) in
-            initial_perms.iter(Size::from_bytes(0), initial_perms.size())
+            inside_perms.iter(Size::from_bytes(0), inside_perms.size())
         {
-            assert!(perm.is_initial());
+            assert!(perm.permission.is_initial());
+            assert_eq!(
+                perm.idempotent_foreign_access,
+                perm.permission.strongest_idempotent_foreign_access(protected)
+            );
+
+            min_sifa = cmp::min(min_sifa, perm.idempotent_foreign_access);
             for (_perms_range, perms) in self
                 .rperms
                 .iter_mut(Size::from_bytes(start) + base_offset, Size::from_bytes(end - start))
             {
-                assert!(
-                    default_strongest_idempotent
-                        >= perm.permission.strongest_idempotent_foreign_access(protected)
-                );
                 perms.insert(idx, perm);
             }
         }
 
-        // Inserting the new perms might have broken the SIFA invariant (see `foreign_access_skipping.rs`).
-        // We now weaken the recorded SIFA for our parents, until the invariant is restored.
-        // We could weaken them all to `LocalAccess`, but it is more efficient to compute the SIFA
-        // for the new permission statically, and use that.
-        // See the comment in `tb_reborrow` for why it is correct to use the SIFA of `default_uninit_perm`.
-        self.update_last_accessed_after_retag(parent_idx, default_strongest_idempotent);
+        // Inserting the new perms might have broken the SIFA invariant (see
+        // `foreign_access_skipping.rs`) if the SIFA we inserted is weaker than that of some parent.
+        // We now weaken the recorded SIFA for our parents, until the invariant is restored. We
+        // could weaken them all to `None`, but it is more efficient to compute the SIFA for the new
+        // permission statically, and use that. For this we need the *minimum* SIFA (`None` needs
+        // more fixup than `Write`).
+        self.update_idempotent_foreign_access_after_retag(parent_idx, min_sifa);
 
         interp_ok(())
     }
 
-    /// Restores the SIFA "children are stronger" invariant after a retag.
-    /// See `foreign_access_skipping` and `new_child`.
-    fn update_last_accessed_after_retag(
+    /// Restores the SIFA "children are stronger"/"parents are weaker" invariant after a retag:
+    /// reduce the SIFA of `current` and its parents to be no stronger than `strongest_allowed`.
+    /// See `foreign_access_skipping.rs` and [`Tree::new_child`].
+    fn update_idempotent_foreign_access_after_retag(
         &mut self,
         mut current: UniIndex,
         strongest_allowed: IdempotentForeignAccess,
     ) {
+        if strongest_allowed == IdempotentForeignAccess::Write {
+            // Nothing is stronger than `Write`.
+            return;
+        }
         // We walk the tree upwards, until the invariant is restored
         loop {
             let current_node = self.nodes.get_mut(current).unwrap();
@@ -755,9 +748,9 @@ impl<'tcx> Tree {
                             == Some(&ProtectorKind::StrongProtector)
                             // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`).
                             // Related to https://github.com/rust-lang/rust/issues/55005.
-                            && !perm.permission().is_cell()
+                            && !perm.permission.is_cell()
                             // Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579.
-                            && perm.is_accessed()
+                            && perm.accessed
                         {
                             Err(TransitionError::ProtectedDealloc)
                         } else {
@@ -790,7 +783,7 @@ impl<'tcx> Tree {
     /// - the access will be applied only to accessed locations of the allocation,
     /// - it will not be visible to children,
     /// - it will be recorded as a `FnExit` diagnostic access
-    /// - and it will be a read except if the location is `Active`, i.e. has been written to,
+    /// - and it will be a read except if the location is `Unique`, i.e. has been written to,
     ///   in which case it will be a write.
     ///
     /// `LocationState::perform_access` will take care of raising transition
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index d9b3696e4f8..189e48eca72 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -106,7 +106,7 @@ fn tree_compacting_is_sound() {
                         as_foreign_or_child(rel),
                         kind,
                         parent.permission(),
-                        as_lazy_or_accessed(child.is_accessed()),
+                        as_lazy_or_accessed(child.accessed()),
                         child.permission(),
                         as_protected(child_protected),
                         np.permission(),
@@ -122,7 +122,7 @@ fn tree_compacting_is_sound() {
                         as_foreign_or_child(rel),
                         kind,
                         parent.permission(),
-                        as_lazy_or_accessed(child.is_accessed()),
+                        as_lazy_or_accessed(child.accessed()),
                         child.permission(),
                         as_protected(child_protected),
                         nc.permission()
@@ -375,7 +375,7 @@ mod spurious_read {
 
     impl LocStateProt {
         fn is_initial(&self) -> bool {
-            self.state.is_initial()
+            self.state.permission().is_initial()
         }
 
         fn perform_access(&self, kind: AccessKind, rel: AccessRelatedness) -> Result<Self, ()> {
@@ -420,7 +420,7 @@ mod spurious_read {
     /// `(LocStateProt, LocStateProt)` where the two states are not guaranteed
     /// to be updated at the same time.
     /// Some `LocStateProtPair` may be unreachable through normal means
-    /// such as `x: Active, y: Active` in the case of mutually foreign pointers.
+    /// such as `x: Unique, y: Unique` in the case of mutually foreign pointers.
     struct LocStateProtPair {
         xy_rel: RelPosXY,
         x: LocStateProt,
@@ -709,7 +709,7 @@ mod spurious_read {
         let mut err = 0;
         for pat in Pattern::exhaustive() {
             let Ok(initial_source) = pat.initial_state() else {
-                // Failed to retag `x` in the source (e.g. `y` was protected Active)
+                // Failed to retag `x` in the source (e.g. `y` was protected Unique)
                 continue;
             };
             // `x` must stay protected, but the function protecting `y` might return here
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index 15d486c27e3..e4e7fb1d725 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -381,8 +381,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // We need to drop our mutex borrow before unblock_thread
                 // because it will be borrowed again in the unblock callback.
                 drop(mutex);
-                if thread_id.is_some() {
-                    this.unblock_thread(thread_id.unwrap(), BlockReason::Mutex)?;
+                if let Some(thread_id) = thread_id {
+                    this.unblock_thread(thread_id, BlockReason::Mutex)?;
                 }
             }
             Some(old_lock_count)
diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs
index b9c99f28594..0cc4342f0d5 100644
--- a/src/tools/miri/src/intrinsics/math.rs
+++ b/src/tools/miri/src/intrinsics/math.rs
@@ -1,4 +1,3 @@
-use rand::Rng;
 use rustc_apfloat::{self, Float, FloatConvert, Round};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, FloatTy};
@@ -39,46 +38,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "sqrtf64" => sqrt::<rustc_apfloat::ieee::Double>(this, args, dest)?,
             "sqrtf128" => sqrt::<rustc_apfloat::ieee::Quad>(this, args, dest)?,
 
-            "fmaf32" => {
-                let [a, b, c] = check_intrinsic_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f32()?;
-                let b = this.read_scalar(b)?.to_f32()?;
-                let c = this.read_scalar(c)?.to_f32()?;
-                let res = a.mul_add(b, c).value;
-                let res = this.adjust_nan(res, &[a, b, c]);
-                this.write_scalar(res, dest)?;
-            }
-            "fmaf64" => {
-                let [a, b, c] = check_intrinsic_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f64()?;
-                let b = this.read_scalar(b)?.to_f64()?;
-                let c = this.read_scalar(c)?.to_f64()?;
-                let res = a.mul_add(b, c).value;
-                let res = this.adjust_nan(res, &[a, b, c]);
-                this.write_scalar(res, dest)?;
-            }
-
-            "fmuladdf32" => {
-                let [a, b, c] = check_intrinsic_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f32()?;
-                let b = this.read_scalar(b)?.to_f32()?;
-                let c = this.read_scalar(c)?.to_f32()?;
-                let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
-                let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value };
-                let res = this.adjust_nan(res, &[a, b, c]);
-                this.write_scalar(res, dest)?;
-            }
-            "fmuladdf64" => {
-                let [a, b, c] = check_intrinsic_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f64()?;
-                let b = this.read_scalar(b)?.to_f64()?;
-                let c = this.read_scalar(c)?.to_f64()?;
-                let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
-                let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value };
-                let res = this.adjust_nan(res, &[a, b, c]);
-                this.write_scalar(res, dest)?;
-            }
-
             #[rustfmt::skip]
             | "fadd_fast"
             | "fsub_fast"
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 04c8bee72c0..d307636e782 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1294,6 +1294,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     }
 
     #[inline(always)]
+    fn float_fuse_mul_add(ecx: &mut InterpCx<'tcx, Self>) -> bool {
+        ecx.machine.float_nondet && ecx.machine.rng.get_mut().random()
+    }
+
+    #[inline(always)]
     fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> {
         interp_ok(ecx.tcx.sess.ub_checks())
     }
diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr
index 449a29088a0..dc8b4f6665a 100644
--- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr
+++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr
@@ -16,7 +16,7 @@ LL | |             Poll::<()>::Pending
 LL | |         })
 LL | |         .await
    | |______________^
-help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [OFFSET]
+help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [OFFSET]
   --> tests/fail/async-shared-mutable.rs:LL:CC
    |
 LL |             *x = 1;
diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr
index 3c8ec7f7d3e..6a1f7761a41 100644
--- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr
@@ -7,7 +7,7 @@ LL |     *y
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC
@@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL | unsafe fn test(mut x: Box<i32>, y: *const i32) -> i32 {
    |                ^^^^^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC
    |
 LL |     *x = 5;
diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr
index 6780e52c3ba..1547a6ca73a 100644
--- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr
@@ -7,7 +7,7 @@ LL |     unsafe { *y = 2 };
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/both_borrows/illegal_write6.rs:LL:CC
@@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL | fn foo(a: &mut u32, y: *mut u32) -> u32 {
    |        ^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/both_borrows/illegal_write6.rs:LL:CC
    |
 LL |     *a = 1;
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr
index 2266a9c39f9..2d9ce2aa1fb 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr
@@ -7,7 +7,7 @@ LL |             Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
@@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL |     y.0 = 0;
    |     ^^^^^^^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
    |
 LL |     y.0 = 0;
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr
index b7f514de0af..42e391b5daf 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr
@@ -7,7 +7,7 @@ LL |             Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call),
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this reborrow (acting as a foreign read access) would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this reborrow (acting as a foreign read access) would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
@@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL |     x
    |     ^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
    |
 LL |     x
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr
index 1995528e9f9..74706d6b9f6 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr
@@ -7,7 +7,7 @@ LL |     unsafe { ptr.write(S(0)) };
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC
@@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL |     unsafe { ptr.write(S(0)) };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC
    |
 LL |     unsafe { ptr.write(S(0)) };
diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr
index e506a61c6bb..c8c0e5c37ef 100644
--- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr
@@ -7,7 +7,7 @@ LL |     unsafe { ptr.read() };
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC
@@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL |     x.0 = 0;
    |     ^^^^^^^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC
    |
 LL |     x.0 = 0;
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr
index b1aa2ba2886..b43e19c3905 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr
@@ -7,7 +7,7 @@ LL |     unsafe { ptr.read() };
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
@@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL |     unsafe { ptr.read() };
    |     ^^^^^^^^^^^^^^^^^^^^^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
    |
 LL |     unsafe { ptr.read() };
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr
index 0cf449ea3ec..deefb24b785 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr
@@ -7,7 +7,7 @@ LL |     unsafe { ptr.write(0) };
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
@@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL |     unsafe { ptr.write(0) };
    |     ^^^^^^^^^^^^^^^^^^^^^^^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
    |
 LL |     unsafe { ptr.write(0) };
diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr
index a006c6feae4..76ccf39744d 100644
--- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr
+++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr
@@ -7,7 +7,7 @@ LL |     unsafe { ptr.write(0) };
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
    = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
-   = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled
+   = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled
    = help: protected tags must never be Disabled
 help: the accessed tag <TAG> was created here
   --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
@@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved
    |
 LL |     unsafe { ptr.write(0) };
    |     ^^^^^^^^^^^^^^^^^^^^^^^
-help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
    |
 LL |     unsafe { ptr.write(0) };
diff --git a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr
index 9e955a6d5b1..aff482abfa0 100644
--- a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr
@@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Reserved
    |
 LL |     let y = unsafe { &mut *(x as *mut u8) };
    |                      ^^^^^^^^^^^^^^^^^^^^
-help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
+help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x1]
   --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC
    |
 LL |     *y += 1; // Success
diff --git a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr
index 7886029dccf..bfd6854514e 100644
--- a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr
@@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Reserved
    |
 LL |     let z = &mut x as *mut i32;
    |             ^^^^^^
-help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC
    |
 LL |         *z = 1;
diff --git a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr
index 2edbbd80569..7a713abcbc4 100644
--- a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr
@@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Reserved
    |
 LL |         let mref = &mut root;
    |                    ^^^^^^^^^
-help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
+help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x1]
   --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC
    |
 LL |         *ptr = 0; // Write
diff --git a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr
index c00c67173b7..9a70d248aa0 100644
--- a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr
@@ -18,7 +18,7 @@ help: the conflicting tag <TAG> was created here, in the initial state Reserved
    |
 LL |     let xref = unsafe { &mut *xraw };
    |                         ^^^^^^^^^^
-help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
+help: the conflicting tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
   --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC
    |
 LL |     *xref = 18; // activate xref
diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
index 024a14600b1..3e5d83911ee 100644
--- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
+++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs
@@ -60,8 +60,7 @@ fn main() {
         fn inner(x: &mut u8, b: IdxBarrier) {
             *x = 42; // activate immediately
             synchronized!(b, "[lazy] retag y (&mut, protect, IM)");
-            // A spurious write should be valid here because `x` is
-            // `Active` and protected.
+            // A spurious write should be valid here because `x` is `Unique` and protected.
             if cfg!(with) {
                 synchronized!(b, "spurious write x (executed)");
                 *x = 64;
diff --git a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr
index ba8ab472872..4b6308847bb 100644
--- a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr
+++ b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr
@@ -18,7 +18,7 @@ help: the conflicting tag <TAG> was created here, in the initial state Reserved
    |
 LL |     let ret = unsafe { &mut (*xraw).1 };
    |                        ^^^^^^^^^^^^^^
-help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x4..0x8]
+help: the conflicting tag <TAG> later transitioned to Unique due to a child write access at offsets [0x4..0x8]
   --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC
    |
 LL |     *ret = *ret; // activate
diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs
index 6514334b09d..94a3bb80544 100644
--- a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs
+++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs
@@ -5,7 +5,7 @@
 
 // When this method is called, the tree will be a single line and look like this,
 // with other_ptr being the root at the top
-// other_ptr = root : Active
+// other_ptr = root : Unique
 // intermediary     : Frozen // an intermediary node
 // m                : Reserved
 fn write_to_mut(m: &mut u8, other_ptr: *const u8) {
diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr b/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr
deleted file mode 100644
index c7d72f70f40..00000000000
--- a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr
+++ /dev/null
@@ -1,32 +0,0 @@
-error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         *uniq.as_ptr() = 3;
-   |         ^^^^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
-   |
-   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
-   = help: the accessed tag <TAG> has state Frozen which forbids this child write access
-help: the accessed tag <TAG> was created here, in the initial state Reserved
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |     let refmut = &mut data;
-   |                  ^^^^^^^^^
-help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         *uniq.as_ptr() = 1; // activation
-   |         ^^^^^^^^^^^^^^^^^^
-   = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
-help: the accessed tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
-  --> tests/fail/tree_borrows/unique.rs:LL:CC
-   |
-LL |         let _definitely_parent = data; // definitely Frozen by now
-   |                                  ^^^^
-   = help: this transition corresponds to a loss of write permissions
-   = note: BACKTRACE (of the first span):
-   = note: inside `main` at tests/fail/tree_borrows/unique.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/pass/0weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs
index c752fc114ba..611733d0dac 100644
--- a/src/tools/miri/tests/pass/0weak_memory/weak.rs
+++ b/src/tools/miri/tests/pass/0weak_memory/weak.rs
@@ -13,6 +13,10 @@ use std::sync::atomic::Ordering::*;
 use std::sync::atomic::{AtomicUsize, fence};
 use std::thread::spawn;
 
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::check_all_outcomes;
+
 #[allow(dead_code)]
 #[derive(Copy, Clone)]
 struct EvilSend<T>(pub T);
@@ -33,35 +37,6 @@ fn spin_until(loc: &AtomicUsize, val: usize) -> usize {
     val
 }
 
-/// Check that the function produces the intended set of outcomes.
-#[track_caller]
-fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Debug>(
-    expected: impl IntoIterator<Item = T>,
-    generate: impl Fn() -> T,
-) {
-    use std::collections::HashSet;
-
-    let expected: HashSet<T> = HashSet::from_iter(expected);
-    let mut seen = HashSet::new();
-    // Let's give it N times as many tries as we are expecting values.
-    let tries = expected.len() * 16;
-    for i in 0..tries {
-        let val = generate();
-        assert!(expected.contains(&val), "got an unexpected value: {val:?}");
-        seen.insert(val);
-        if i > tries / 2 && expected.len() == seen.len() {
-            // We saw everything and we did quite a few tries, let's avoid wasting time.
-            return;
-        }
-    }
-    // Let's see if we saw them all.
-    for val in expected {
-        if !seen.contains(&val) {
-            panic!("did not get value that should be possible: {val:?}");
-        }
-    }
-}
-
 fn relaxed() {
     check_all_outcomes([0, 1, 2], || {
         let x = static_atomic(0);
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 3ce5ea8356b..67a14c2b389 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -8,12 +8,16 @@
 #![allow(internal_features)]
 #![allow(unnecessary_transmutes)]
 
+#[path = "../utils/mod.rs"]
+mod utils;
 use std::any::type_name;
 use std::cmp::min;
 use std::fmt::{Debug, Display, LowerHex};
 use std::hint::black_box;
 use std::{f32, f64};
 
+use utils::check_nondet;
+
 /// Compare the two floats, allowing for $ulp many ULPs of error.
 ///
 /// ULP means "Units in the Last Place" or "Units of Least Precision".
@@ -1415,12 +1419,12 @@ fn test_fmuladd() {
 
     #[inline(never)]
     pub fn test_operations_f32(a: f32, b: f32, c: f32) {
-        assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c);
+        assert_approx_eq!(fmuladdf32(a, b, c), a * b + c);
     }
 
     #[inline(never)]
     pub fn test_operations_f64(a: f64, b: f64, c: f64) {
-        assert_approx_eq!(unsafe { fmuladdf64(a, b, c) }, a * b + c);
+        assert_approx_eq!(fmuladdf64(a, b, c), a * b + c);
     }
 
     test_operations_f32(0.1, 0.2, 0.3);
@@ -1429,29 +1433,14 @@ fn test_fmuladd() {
 
 /// `min` and `max` on equal arguments are non-deterministic.
 fn test_min_max_nondet() {
-    /// Ensure that if we call the closure often enough, we see both `true` and `false.`
-    #[track_caller]
-    fn ensure_both(f: impl Fn() -> bool) {
-        let rounds = 32;
-        let first = f();
-        for _ in 1..rounds {
-            if f() != first {
-                // We saw two different values!
-                return;
-            }
-        }
-        // We saw the same thing N times.
-        panic!("expected non-determinism, got {rounds} times the same result: {first:?}");
-    }
-
-    ensure_both(|| f16::min(0.0, -0.0).is_sign_positive());
-    ensure_both(|| f16::max(0.0, -0.0).is_sign_positive());
-    ensure_both(|| f32::min(0.0, -0.0).is_sign_positive());
-    ensure_both(|| f32::max(0.0, -0.0).is_sign_positive());
-    ensure_both(|| f64::min(0.0, -0.0).is_sign_positive());
-    ensure_both(|| f64::max(0.0, -0.0).is_sign_positive());
-    ensure_both(|| f128::min(0.0, -0.0).is_sign_positive());
-    ensure_both(|| f128::max(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f16::min(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f16::max(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f32::min(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f32::max(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f64::min(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f64::max(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f128::min(0.0, -0.0).is_sign_positive());
+    check_nondet(|| f128::max(0.0, -0.0).is_sign_positive());
 }
 
 fn test_non_determinism() {
@@ -1461,35 +1450,20 @@ fn test_non_determinism() {
     };
     use std::{f32, f64};
 
-    /// Ensure that the operation is non-deterministic
-    #[track_caller]
-    fn ensure_nondet<T: PartialEq + std::fmt::Debug>(f: impl Fn() -> T) {
-        let rounds = 16;
-        let first = f();
-        for _ in 1..rounds {
-            if f() != first {
-                // We saw two different values!
-                return;
-            }
-        }
-        // We saw the same thing N times.
-        panic!("expected non-determinism, got {rounds} times the same result: {first:?}");
-    }
-
     macro_rules! test_operations_f {
         ($a:expr, $b:expr) => {
-            ensure_nondet(|| fadd_algebraic($a, $b));
-            ensure_nondet(|| fsub_algebraic($a, $b));
-            ensure_nondet(|| fmul_algebraic($a, $b));
-            ensure_nondet(|| fdiv_algebraic($a, $b));
-            ensure_nondet(|| frem_algebraic($a, $b));
+            check_nondet(|| fadd_algebraic($a, $b));
+            check_nondet(|| fsub_algebraic($a, $b));
+            check_nondet(|| fmul_algebraic($a, $b));
+            check_nondet(|| fdiv_algebraic($a, $b));
+            check_nondet(|| frem_algebraic($a, $b));
 
             unsafe {
-                ensure_nondet(|| fadd_fast($a, $b));
-                ensure_nondet(|| fsub_fast($a, $b));
-                ensure_nondet(|| fmul_fast($a, $b));
-                ensure_nondet(|| fdiv_fast($a, $b));
-                ensure_nondet(|| frem_fast($a, $b));
+                check_nondet(|| fadd_fast($a, $b));
+                check_nondet(|| fsub_fast($a, $b));
+                check_nondet(|| fmul_fast($a, $b));
+                check_nondet(|| fdiv_fast($a, $b));
+                check_nondet(|| frem_fast($a, $b));
             }
         };
     }
@@ -1499,70 +1473,70 @@ fn test_non_determinism() {
     }
     pub fn test_operations_f32(a: f32, b: f32) {
         test_operations_f!(a, b);
-        ensure_nondet(|| a.powf(b));
-        ensure_nondet(|| a.powi(2));
-        ensure_nondet(|| a.log(b));
-        ensure_nondet(|| a.exp());
-        ensure_nondet(|| 10f32.exp2());
-        ensure_nondet(|| f32::consts::E.ln());
-        ensure_nondet(|| 10f32.log10());
-        ensure_nondet(|| 8f32.log2());
-        ensure_nondet(|| 1f32.ln_1p());
-        ensure_nondet(|| 27.0f32.cbrt());
-        ensure_nondet(|| 3.0f32.hypot(4.0f32));
-        ensure_nondet(|| 1f32.sin());
-        ensure_nondet(|| 1f32.cos());
+        check_nondet(|| a.powf(b));
+        check_nondet(|| a.powi(2));
+        check_nondet(|| a.log(b));
+        check_nondet(|| a.exp());
+        check_nondet(|| 10f32.exp2());
+        check_nondet(|| f32::consts::E.ln());
+        check_nondet(|| 10f32.log10());
+        check_nondet(|| 8f32.log2());
+        check_nondet(|| 1f32.ln_1p());
+        check_nondet(|| 27.0f32.cbrt());
+        check_nondet(|| 3.0f32.hypot(4.0f32));
+        check_nondet(|| 1f32.sin());
+        check_nondet(|| 1f32.cos());
         // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version,
         // which means the little rounding errors Miri introduces are discarded by the cast down to
         // `f32`. Just skip the test for them.
         if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) {
-            ensure_nondet(|| 1.0f32.tan());
-            ensure_nondet(|| 1.0f32.asin());
-            ensure_nondet(|| 5.0f32.acos());
-            ensure_nondet(|| 1.0f32.atan());
-            ensure_nondet(|| 1.0f32.atan2(2.0f32));
-            ensure_nondet(|| 1.0f32.sinh());
-            ensure_nondet(|| 1.0f32.cosh());
-            ensure_nondet(|| 1.0f32.tanh());
+            check_nondet(|| 1.0f32.tan());
+            check_nondet(|| 1.0f32.asin());
+            check_nondet(|| 5.0f32.acos());
+            check_nondet(|| 1.0f32.atan());
+            check_nondet(|| 1.0f32.atan2(2.0f32));
+            check_nondet(|| 1.0f32.sinh());
+            check_nondet(|| 1.0f32.cosh());
+            check_nondet(|| 1.0f32.tanh());
         }
-        ensure_nondet(|| 1.0f32.asinh());
-        ensure_nondet(|| 2.0f32.acosh());
-        ensure_nondet(|| 0.5f32.atanh());
-        ensure_nondet(|| 5.0f32.gamma());
-        ensure_nondet(|| 5.0f32.ln_gamma());
-        ensure_nondet(|| 5.0f32.erf());
-        ensure_nondet(|| 5.0f32.erfc());
+        check_nondet(|| 1.0f32.asinh());
+        check_nondet(|| 2.0f32.acosh());
+        check_nondet(|| 0.5f32.atanh());
+        check_nondet(|| 5.0f32.gamma());
+        check_nondet(|| 5.0f32.ln_gamma());
+        check_nondet(|| 5.0f32.erf());
+        check_nondet(|| 5.0f32.erfc());
     }
     pub fn test_operations_f64(a: f64, b: f64) {
         test_operations_f!(a, b);
-        ensure_nondet(|| a.powf(b));
-        ensure_nondet(|| a.powi(2));
-        ensure_nondet(|| a.log(b));
-        ensure_nondet(|| a.exp());
-        ensure_nondet(|| 50f64.exp2());
-        ensure_nondet(|| 3f64.ln());
-        ensure_nondet(|| f64::consts::E.log10());
-        ensure_nondet(|| f64::consts::E.log2());
-        ensure_nondet(|| 1f64.ln_1p());
-        ensure_nondet(|| 27.0f64.cbrt());
-        ensure_nondet(|| 3.0f64.hypot(4.0f64));
-        ensure_nondet(|| 1f64.sin());
-        ensure_nondet(|| 1f64.cos());
-        ensure_nondet(|| 1.0f64.tan());
-        ensure_nondet(|| 1.0f64.asin());
-        ensure_nondet(|| 5.0f64.acos());
-        ensure_nondet(|| 1.0f64.atan());
-        ensure_nondet(|| 1.0f64.atan2(2.0f64));
-        ensure_nondet(|| 1.0f64.sinh());
-        ensure_nondet(|| 1.0f64.cosh());
-        ensure_nondet(|| 1.0f64.tanh());
-        ensure_nondet(|| 1.0f64.asinh());
-        ensure_nondet(|| 3.0f64.acosh());
-        ensure_nondet(|| 0.5f64.atanh());
-        ensure_nondet(|| 5.0f64.gamma());
-        ensure_nondet(|| 5.0f64.ln_gamma());
-        ensure_nondet(|| 5.0f64.erf());
-        ensure_nondet(|| 5.0f64.erfc());
+        check_nondet(|| a.powf(b));
+        check_nondet(|| a.powi(2));
+        check_nondet(|| a.log(b));
+        check_nondet(|| a.exp());
+        check_nondet(|| 50f64.exp2());
+        check_nondet(|| 3f64.ln());
+        check_nondet(|| f64::consts::E.log10());
+        check_nondet(|| f64::consts::E.log2());
+        check_nondet(|| 1f64.ln_1p());
+        check_nondet(|| 27.0f64.cbrt());
+        check_nondet(|| 3.0f64.hypot(4.0f64));
+        check_nondet(|| 1f64.sin());
+        check_nondet(|| 1f64.cos());
+        check_nondet(|| 1.0f64.tan());
+        check_nondet(|| 1.0f64.asin());
+        check_nondet(|| 5.0f64.acos());
+        check_nondet(|| 1.0f64.atan());
+        check_nondet(|| 1.0f64.atan2(2.0f64));
+        check_nondet(|| 1.0f64.sinh());
+        check_nondet(|| 1.0f64.cosh());
+        check_nondet(|| 1.0f64.tanh());
+        check_nondet(|| 1.0f64.asinh());
+        check_nondet(|| 3.0f64.acosh());
+        check_nondet(|| 0.5f64.atanh());
+        check_nondet(|| 5.0f64.gamma());
+        check_nondet(|| 5.0f64.ln_gamma());
+        check_nondet(|| 5.0f64.erf());
+        check_nondet(|| 5.0f64.erfc());
     }
     pub fn test_operations_f128(a: f128, b: f128) {
         test_operations_f!(a, b);
@@ -1574,15 +1548,15 @@ fn test_non_determinism() {
     test_operations_f128(25., 18.);
 
     // SNaN^0 = (1 | NaN)
-    ensure_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan());
-    ensure_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan());
+    check_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan());
+    check_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan());
 
     // 1^SNaN = (1 | NaN)
-    ensure_nondet(|| f32::powf(1.0, SNAN_F32).is_nan());
-    ensure_nondet(|| f64::powf(1.0, SNAN_F64).is_nan());
+    check_nondet(|| f32::powf(1.0, SNAN_F32).is_nan());
+    check_nondet(|| f64::powf(1.0, SNAN_F64).is_nan());
 
     // same as powf (keep it consistent):
     // x^SNaN = (1 | NaN)
-    ensure_nondet(|| f32::powi(SNAN_F32, 0).is_nan());
-    ensure_nondet(|| f64::powi(SNAN_F64, 0).is_nan());
+    check_nondet(|| f32::powi(SNAN_F32, 0).is_nan());
+    check_nondet(|| f64::powi(SNAN_F64, 0).is_nan());
 }
diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs
index 90281630740..c07ffdf9740 100644
--- a/src/tools/miri/tests/pass/float_nan.rs
+++ b/src/tools/miri/tests/pass/float_nan.rs
@@ -5,6 +5,10 @@
 use std::fmt;
 use std::hint::black_box;
 
+#[path = "../utils/mod.rs"]
+mod utils;
+use utils::check_all_outcomes;
+
 fn ldexp(a: f64, b: i32) -> f64 {
     extern "C" {
         fn ldexp(x: f64, n: i32) -> f64;
@@ -26,35 +30,6 @@ enum NaNKind {
 }
 use NaNKind::*;
 
-/// Check that the function produces the intended set of outcomes.
-#[track_caller]
-fn check_all_outcomes<T: Eq + std::hash::Hash + fmt::Display>(
-    expected: impl IntoIterator<Item = T>,
-    generate: impl Fn() -> T,
-) {
-    use std::collections::HashSet;
-
-    let expected: HashSet<T> = HashSet::from_iter(expected);
-    let mut seen = HashSet::new();
-    // Let's give it N times as many tries as we are expecting values.
-    let tries = expected.len() * 12;
-    for i in 0..tries {
-        let val = generate();
-        assert!(expected.contains(&val), "got an unexpected value: {val}");
-        seen.insert(val);
-        if i > tries / 2 && expected.len() == seen.len() {
-            // We saw everything and we did quite a few tries, let's avoid wasting time.
-            return;
-        }
-    }
-    // Let's see if we saw them all.
-    for val in expected {
-        if !seen.contains(&val) {
-            panic!("did not get value that should be possible: {val}");
-        }
-    }
-}
-
 // -- f32 support
 #[repr(C)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
@@ -81,7 +56,7 @@ const F32_EXP: u32 = 8; // 8 bits of exponent
 const F32_MANTISSA: u32 = F32_SIGN_BIT - F32_EXP;
 const F32_NAN_PAYLOAD: u32 = F32_MANTISSA - 1;
 
-impl fmt::Display for F32 {
+impl fmt::Debug for F32 {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // Alaways show raw bits.
         write!(f, "0x{:08x} ", self.0)?;
@@ -154,7 +129,7 @@ const F64_EXP: u32 = 11; // 11 bits of exponent
 const F64_MANTISSA: u32 = F64_SIGN_BIT - F64_EXP;
 const F64_NAN_PAYLOAD: u32 = F64_MANTISSA - 1;
 
-impl fmt::Display for F64 {
+impl fmt::Debug for F64 {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // Alaways show raw bits.
         write!(f, "0x{:08x} ", self.0)?;
diff --git a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs
index b688405c4b1..abc156d49cb 100644
--- a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs
+++ b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs
@@ -3,73 +3,48 @@ use std::intrinsics::simd::simd_relaxed_fma;
 use std::intrinsics::{fmuladdf32, fmuladdf64};
 use std::simd::prelude::*;
 
-fn ensure_both_happen(f: impl Fn() -> bool) -> bool {
-    let mut saw_true = false;
-    let mut saw_false = false;
-    for _ in 0..50 {
-        let b = f();
-        if b {
-            saw_true = true;
-        } else {
-            saw_false = true;
-        }
-        if saw_true && saw_false {
-            return true;
-        }
-    }
-    false
-}
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::check_nondet;
 
 fn main() {
-    assert!(
-        ensure_both_happen(|| {
-            let a = std::hint::black_box(0.1_f64);
-            let b = std::hint::black_box(0.2);
-            let c = std::hint::black_box(-a * b);
-            // It is unspecified whether the following operation is fused or not. The
-            // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused.
-            let x = unsafe { fmuladdf64(a, b, c) };
-            x == 0.0
-        }),
-        "`fmuladdf64` failed to be evaluated as both fused and unfused"
-    );
+    check_nondet(|| {
+        let a = std::hint::black_box(0.1_f64);
+        let b = std::hint::black_box(0.2);
+        let c = std::hint::black_box(-a * b);
+        // It is unspecified whether the following operation is fused or not. The
+        // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused.
+        let x = fmuladdf64(a, b, c);
+        x == 0.0
+    });
 
-    assert!(
-        ensure_both_happen(|| {
-            let a = std::hint::black_box(0.1_f32);
-            let b = std::hint::black_box(0.2);
-            let c = std::hint::black_box(-a * b);
-            // It is unspecified whether the following operation is fused or not. The
-            // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused.
-            let x = unsafe { fmuladdf32(a, b, c) };
-            x == 0.0
-        }),
-        "`fmuladdf32` failed to be evaluated as both fused and unfused"
-    );
+    check_nondet(|| {
+        let a = std::hint::black_box(0.1_f32);
+        let b = std::hint::black_box(0.2);
+        let c = std::hint::black_box(-a * b);
+        // It is unspecified whether the following operation is fused or not. The
+        // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused.
+        let x = fmuladdf32(a, b, c);
+        x == 0.0
+    });
 
-    assert!(
-        ensure_both_happen(|| {
-            let a = f32x4::splat(std::hint::black_box(0.1));
-            let b = f32x4::splat(std::hint::black_box(0.2));
-            let c = std::hint::black_box(-a * b);
-            let x = unsafe { simd_relaxed_fma(a, b, c) };
-            // Whether we fuse or not is a per-element decision, so sometimes these should be
-            // the same and sometimes not.
-            x[0] == x[1]
-        }),
-        "`simd_relaxed_fma` failed to be evaluated as both fused and unfused"
-    );
+    check_nondet(|| {
+        let a = f32x4::splat(std::hint::black_box(0.1));
+        let b = f32x4::splat(std::hint::black_box(0.2));
+        let c = std::hint::black_box(-a * b);
+        let x = unsafe { simd_relaxed_fma(a, b, c) };
+        // Whether we fuse or not is a per-element decision, so sometimes these should be
+        // the same and sometimes not.
+        x[0] == x[1]
+    });
 
-    assert!(
-        ensure_both_happen(|| {
-            let a = f64x4::splat(std::hint::black_box(0.1));
-            let b = f64x4::splat(std::hint::black_box(0.2));
-            let c = std::hint::black_box(-a * b);
-            let x = unsafe { simd_relaxed_fma(a, b, c) };
-            // Whether we fuse or not is a per-element decision, so sometimes these should be
-            // the same and sometimes not.
-            x[0] == x[1]
-        }),
-        "`simd_relaxed_fma` failed to be evaluated as both fused and unfused"
-    );
+    check_nondet(|| {
+        let a = f64x4::splat(std::hint::black_box(0.1));
+        let b = f64x4::splat(std::hint::black_box(0.2));
+        let c = std::hint::black_box(-a * b);
+        let x = unsafe { simd_relaxed_fma(a, b, c) };
+        // Whether we fuse or not is a per-element decision, so sometimes these should be
+        // the same and sometimes not.
+        x[0] == x[1]
+    });
 }
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs
index adf2f4e845b..4a868455c84 100644
--- a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs
@@ -20,7 +20,7 @@ pub fn main() {
         name!(ptr2);
 
         // We perform a write through `x`.
-        // Because `ptr1` is ReservedIM, a child write will make it transition to Active.
+        // Because `ptr1` is ReservedIM, a child write will make it transition to Unique.
         // Because `ptr2` is ReservedIM, a foreign write doesn't have any effect on it.
         let x = (*ptr1).get();
         *x = 1;
diff --git a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs
index 4fbccef2367..edd649b91ed 100644
--- a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs
@@ -6,7 +6,7 @@
 mod utils;
 
 // To check that a reborrow is counted as a Read access, we use a reborrow
-// with no additional Read to Freeze an Active pointer.
+// with no additional Read to Freeze an Unique pointer.
 
 fn main() {
     unsafe {
@@ -15,7 +15,7 @@ fn main() {
         let alloc_id = alloc_id!(parent);
         let x = &mut *parent;
         name!(x);
-        *x = 0; // x is now Active
+        *x = 0; // x is now Unique
         print_state!(alloc_id);
         let y = &mut *parent;
         name!(y);
diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.rs b/src/tools/miri/tests/pass/tree_borrows/reserved.rs
index c57cd7fcf0a..83e1d9c70ed 100644
--- a/src/tools/miri/tests/pass/tree_borrows/reserved.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/reserved.rs
@@ -68,7 +68,7 @@ unsafe fn cell_unprotected_read() {
 }
 
 // Foreign Write on an interior mutable pointer is a noop.
-// Also y must become Active.
+// Also y must become Unique.
 unsafe fn cell_unprotected_write() {
     print("[interior mut] Foreign Write: Re* -> Re*");
     let base = &mut UnsafeCell::new(0u64);
@@ -97,7 +97,7 @@ unsafe fn int_protected_read() {
 }
 
 // Foreign Read on a Reserved is a noop.
-// Also y must become Active.
+// Also y must become Unique.
 unsafe fn int_unprotected_read() {
     print("[] Foreign Read: Res -> Res");
     let base = &mut 0u8;
diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs
index 3e526813bb4..8b1b1e143b1 100644
--- a/src/tools/miri/tests/pass/vec.rs
+++ b/src/tools/miri/tests/pass/vec.rs
@@ -169,6 +169,15 @@ fn miri_issue_2759() {
     input.replace_range(0..0, "0");
 }
 
+/// This was skirting the edge of UB, let's make sure it remains on the sound side.
+/// Context: <https://github.com/rust-lang/rust/pull/141032>.
+fn extract_if() {
+    let mut v = vec![Box::new(0u64), Box::new(1u64)];
+    for item in v.extract_if(.., |x| **x == 0) {
+        drop(item);
+    }
+}
+
 fn main() {
     assert_eq!(vec_reallocate().len(), 5);
 
@@ -199,4 +208,5 @@ fn main() {
     swap_remove();
     reverse();
     miri_issue_2759();
+    extract_if();
 }
diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs
index 138ada4e20d..37f99962163 100644
--- a/src/tools/miri/tests/utils/mod.rs
+++ b/src/tools/miri/tests/utils/mod.rs
@@ -16,3 +16,53 @@ pub fn run_provenance_gc() {
     // SAFETY: No preconditions. The GC is fine to run at any time.
     unsafe { miri_run_provenance_gc() }
 }
+
+/// Check that the function produces the intended set of outcomes.
+#[track_caller]
+pub fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Debug>(
+    expected: impl IntoIterator<Item = T>,
+    generate: impl Fn() -> T,
+) {
+    use std::collections::HashSet;
+
+    let expected: HashSet<T> = HashSet::from_iter(expected);
+    let mut seen = HashSet::new();
+    // Let's give it N times as many tries as we are expecting values.
+    let min_tries = std::cmp::max(20, expected.len() * 4);
+    let max_tries = expected.len() * 50;
+    for i in 0..max_tries {
+        let val = generate();
+        assert!(expected.contains(&val), "got an unexpected value: {val:?}");
+        seen.insert(val);
+        if i >= min_tries && expected.len() == seen.len() {
+            // We saw everything and we did enough tries, let's avoid wasting time.
+            return;
+        }
+    }
+    // Let's see if we saw them all.
+    if expected.len() == seen.len() {
+        return;
+    }
+    // Find the missing one.
+    for val in expected {
+        if !seen.contains(&val) {
+            panic!("did not get value that should be possible: {val:?}");
+        }
+    }
+    unreachable!()
+}
+
+/// Check that the operation is non-deterministic
+#[track_caller]
+pub fn check_nondet<T: PartialEq + std::fmt::Debug>(f: impl Fn() -> T) {
+    let rounds = 50;
+    let first = f();
+    for _ in 1..rounds {
+        if f() != first {
+            // We saw two different values!
+            return;
+        }
+    }
+    // We saw the same thing N times.
+    panic!("expected non-determinism, got {rounds} times the same result: {first:?}");
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 301d4cca066..e5c213ca937 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -15,10 +15,6 @@ extern crate rustc_parse_format;
 #[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_parse_format as rustc_parse_format;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_abi;
-
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_abi as rustc_abi;
 
 pub mod db;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
index 15e68ff95cd..0fa412ad7fa 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
@@ -12,7 +12,7 @@ use tracing::debug;
 
 use crate::{
     ExpandError, ExpandResult, MacroCallId,
-    builtin::quote::{dollar_crate, quote},
+    builtin::quote::dollar_crate,
     db::ExpandDatabase,
     hygiene::span_with_def_site_ctxt,
     name::{self, AsName, Name},
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index ec344613761..6fe63f249cd 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -19,7 +19,7 @@ use syntax_bridge::syntax_node_to_token_tree;
 
 use crate::{
     EditionedFileId, ExpandError, ExpandResult, Lookup as _, MacroCallId,
-    builtin::quote::{WithDelimiter, dollar_crate, quote},
+    builtin::quote::{WithDelimiter, dollar_crate},
     db::ExpandDatabase,
     hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
     name,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
index 70c38d4d7c7..84dd4a24d90 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
@@ -229,8 +229,6 @@ mod tests {
     use span::{Edition, ROOT_ERASED_FILE_AST_ID, SpanAnchor, SyntaxContext};
     use syntax::{TextRange, TextSize};
 
-    use super::quote;
-
     const DUMMY: tt::Span = tt::Span {
         range: TextRange::empty(TextSize::new(0)),
         anchor: SpanAnchor {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 451622ef747..2e59a488e67 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -3,45 +3,24 @@
 
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_index;
+// FIXME: We used to import `rustc_*` deps from `rustc_private` with `feature = "in-rust-tree" but
+// temporarily switched to crates.io versions due to hardships that working on them from rustc
+// demands corresponding changes on rust-analyzer at the same time.
+// For details, see the zulip discussion below:
+// https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/relying.20on.20in-tree.20.60rustc_type_ir.60.2F.60rustc_next_trait_solver.60/with/541055689
 
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_index as rustc_index;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_abi;
-
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_abi as rustc_abi;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_pattern_analysis;
-
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_ast_ir;
-
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_ast_ir as rustc_ast_ir;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_type_ir;
-
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_type_ir as rustc_type_ir;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_next_trait_solver;
-
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver;
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_data_structures as ena;
-
 mod builder;
 mod chalk_db;
 mod chalk_ext;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs
index 7ebefa76ed0..0b3582051bc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs
@@ -36,8 +36,6 @@ impl<'db> Const<'db> {
             internee: kind,
             flags: flags.flags,
             outer_exclusive_binder: flags.outer_exclusive_binder,
-            #[cfg(feature = "in-rust-tree")]
-            stable_hash: ena::fingerprint::Fingerprint::ZERO,
         };
         Const::new_(interner.db(), InternedWrapperNoDebug(cached))
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs
index 86545415009..99b1354b633 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs
@@ -227,8 +227,6 @@ impl<'db> Predicate<'db> {
             internee: kind,
             flags: flags.flags,
             outer_exclusive_binder: flags.outer_exclusive_binder,
-            #[cfg(feature = "in-rust-tree")]
-            stable_hash: ena::fingerprint::Fingerprint::ZERO,
         };
         Predicate::new_(interner.db(), InternedWrapperNoDebug(cached))
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
index c7a747ade3e..70139e86669 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
@@ -60,8 +60,6 @@ impl<'db> Ty<'db> {
             internee: kind,
             flags: flags.flags,
             outer_exclusive_binder: flags.outer_exclusive_binder,
-            #[cfg(feature = "in-rust-tree")]
-            stable_hash: ena::fingerprint::Fingerprint::ZERO,
         };
         Ty::new_(interner.db(), InternedWrapperNoDebug(cached))
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index f8dacf0fb86..027a386abe8 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -20,10 +20,6 @@
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 #![recursion_limit = "512"]
 
-#[cfg(feature = "in-rust-tree")]
-extern crate rustc_type_ir;
-
-#[cfg(not(feature = "in-rust-tree"))]
 extern crate ra_ap_rustc_type_ir as rustc_type_ir;
 
 mod attrs;
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index 6b63108c037..525953bf445 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -516,7 +516,6 @@ mod test {
     #[allow(dead_code)]
     mod mock {
         use super::super::*;
-        use crate::config_option_with_style_edition_default;
         use rustfmt_config_proc_macro::config_type;
 
         #[config_type]
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
index 9ddce725106..f93d3b56113 100644
--- a/src/tools/tidy/src/alphabetical.rs
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -24,6 +24,7 @@ use std::fmt::Display;
 use std::iter::Peekable;
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
 use crate::walk::{filter_dirs, walk};
 
 #[cfg(test)]
@@ -43,8 +44,7 @@ const END_MARKER: &str = "tidy-alphabetical-end";
 fn check_section<'a>(
     file: impl Display,
     lines: impl Iterator<Item = (usize, &'a str)>,
-    err: &mut dyn FnMut(&str) -> std::io::Result<()>,
-    bad: &mut bool,
+    check: &mut RunningCheck,
 ) {
     let mut prev_line = String::new();
     let mut first_indent = None;
@@ -56,12 +56,10 @@ fn check_section<'a>(
         }
 
         if line.contains(START_MARKER) {
-            tidy_error_ext!(
-                err,
-                bad,
+            check.error(format!(
                 "{file}:{} found `{START_MARKER}` expecting `{END_MARKER}`",
                 idx + 1
-            );
+            ));
             return;
         }
 
@@ -104,45 +102,44 @@ fn check_section<'a>(
         let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ');
 
         if version_sort(trimmed_line, prev_line_trimmed_lowercase).is_lt() {
-            tidy_error_ext!(err, bad, "{file}:{}: line not in alphabetical order", idx + 1);
+            check.error(format!("{file}:{}: line not in alphabetical order", idx + 1));
         }
 
         prev_line = line;
     }
 
-    tidy_error_ext!(err, bad, "{file}: reached end of file expecting `{END_MARKER}`")
+    check.error(format!("{file}: reached end of file expecting `{END_MARKER}`"));
 }
 
 fn check_lines<'a>(
     file: &impl Display,
     mut lines: impl Iterator<Item = (usize, &'a str)>,
-    err: &mut dyn FnMut(&str) -> std::io::Result<()>,
-    bad: &mut bool,
+    check: &mut RunningCheck,
 ) {
     while let Some((idx, line)) = lines.next() {
         if line.contains(END_MARKER) {
-            tidy_error_ext!(
-                err,
-                bad,
+            check.error(format!(
                 "{file}:{} found `{END_MARKER}` expecting `{START_MARKER}`",
                 idx + 1
-            )
+            ));
         }
 
         if line.contains(START_MARKER) {
-            check_section(file, &mut lines, err, bad);
+            check_section(file, &mut lines, check);
         }
     }
 }
 
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("alphabetical").path(path));
+
     let skip =
         |path: &_, _is_dir| filter_dirs(path) || path.ends_with("tidy/src/alphabetical/tests.rs");
 
     walk(path, skip, &mut |entry, contents| {
         let file = &entry.path().display();
         let lines = contents.lines().enumerate();
-        check_lines(file, lines, &mut crate::tidy_error, bad)
+        check_lines(file, lines, &mut check)
     });
 }
 
diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs
index 4d05bc33ced..b181ab8f744 100644
--- a/src/tools/tidy/src/alphabetical/tests.rs
+++ b/src/tools/tidy/src/alphabetical/tests.rs
@@ -1,19 +1,22 @@
-use std::io::Write;
-use std::str::from_utf8;
+use std::path::Path;
 
-use super::*;
+use crate::alphabetical::check_lines;
+use crate::diagnostics::DiagCtx;
 
 #[track_caller]
 fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) {
-    let mut actual_msg = Vec::new();
-    let mut actual_bad = false;
-    let mut err = |args: &_| {
-        write!(&mut actual_msg, "{args}")?;
-        Ok(())
-    };
-    check_lines(&name, lines.lines().enumerate(), &mut err, &mut actual_bad);
-    assert_eq!(expected_msg, from_utf8(&actual_msg).unwrap());
-    assert_eq!(expected_bad, actual_bad);
+    let diag_ctx = DiagCtx::new(Path::new("/"), false);
+    let mut check = diag_ctx.start_check("alphabetical-test");
+    check_lines(&name, lines.lines().enumerate(), &mut check);
+
+    assert_eq!(expected_bad, check.is_bad());
+    let errors = check.get_errors();
+    if expected_bad {
+        assert_eq!(errors.len(), 1);
+        assert_eq!(expected_msg, errors[0]);
+    } else {
+        assert!(errors.is_empty());
+    }
 }
 
 #[track_caller]
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index a18f549844b..10b61869971 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -12,11 +12,13 @@ pub use os_impl::*;
 mod os_impl {
     use std::path::Path;
 
+    use crate::diagnostics::DiagCtx;
+
     pub fn check_filesystem_support(_sources: &[&Path], _output: &Path) -> bool {
         return false;
     }
 
-    pub fn check(_path: &Path, _bad: &mut bool) {}
+    pub fn check(_path: &Path, _diag_ctx: DiagCtx) {}
 }
 
 #[cfg(unix)]
@@ -36,6 +38,8 @@ mod os_impl {
 
     use FilesystemSupport::*;
 
+    use crate::diagnostics::DiagCtx;
+
     fn is_executable(path: &Path) -> std::io::Result<bool> {
         Ok(path.metadata()?.mode() & 0o111 != 0)
     }
@@ -106,14 +110,16 @@ mod os_impl {
     }
 
     #[cfg(unix)]
-    pub fn check(path: &Path, bad: &mut bool) {
+    pub fn check(path: &Path, diag_ctx: DiagCtx) {
+        let mut check = diag_ctx.start_check("bins");
+
         use std::ffi::OsStr;
 
         const ALLOWED: &[&str] = &["configure", "x"];
 
         for p in RI_EXCLUSION_LIST {
             if !path.join(Path::new(p)).exists() {
-                tidy_error!(bad, "rust-installer test bins missed: {p}");
+                check.error(format!("rust-installer test bins missed: {p}"));
             }
         }
 
@@ -153,7 +159,7 @@ mod os_impl {
                         });
                     let path_bytes = rel_path.as_os_str().as_bytes();
                     if output.status.success() && output.stdout.starts_with(path_bytes) {
-                        tidy_error!(bad, "binary checked into source: {}", file.display());
+                        check.error(format!("binary checked into source: {}", file.display()));
                     }
                 }
             },
diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs
index 645534cc827..19effaede81 100644
--- a/src/tools/tidy/src/debug_artifacts.rs
+++ b/src/tools/tidy/src/debug_artifacts.rs
@@ -2,24 +2,25 @@
 
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::walk::{filter_dirs, filter_not_rust, walk};
 
 const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test";
 
-pub fn check(test_dir: &Path, bad: &mut bool) {
+pub fn check(test_dir: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("debug_artifacts").path(test_dir));
+
     walk(
         test_dir,
         |path, _is_dir| filter_dirs(path) || filter_not_rust(path),
         &mut |entry, contents| {
             for (i, line) in contents.lines().enumerate() {
                 if line.contains("borrowck_graphviz_postflow") {
-                    tidy_error!(
-                        bad,
-                        "{}:{}: {}",
+                    check.error(format!(
+                        "{}:{}: {GRAPHVIZ_POSTFLOW_MSG}",
                         entry.path().display(),
-                        i + 1,
-                        GRAPHVIZ_POSTFLOW_MSG
-                    );
+                        i + 1
+                    ));
                 }
             }
         },
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 568ec0c1198..c76b46ec2bf 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -9,6 +9,8 @@ use build_helper::ci::CiEnv;
 use cargo_metadata::semver::Version;
 use cargo_metadata::{Metadata, Package, PackageId};
 
+use crate::diagnostics::{DiagCtx, RunningCheck};
+
 #[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"]
 mod proc_macro_deps;
 
@@ -365,6 +367,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "expect-test",
     "fallible-iterator", // dependency of `thorin`
     "fastrand",
+    "find-msvc-tools",
     "flate2",
     "fluent-bundle",
     "fluent-langneg",
@@ -575,6 +578,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     "rustc-literal-escaper",
     "shlex",
     "unwinding",
+    "vex-sdk",
     "wasi",
     "windows-sys",
     "windows-targets",
@@ -661,10 +665,12 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
 ///
 /// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
 /// to the cargo executable.
-pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
+pub fn check(root: &Path, cargo: &Path, bless: bool, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("deps");
+
     let mut checked_runtime_licenses = false;
 
-    check_proc_macro_dep_list(root, cargo, bless, bad);
+    check_proc_macro_dep_list(root, cargo, bless, &mut check);
 
     for &WorkspaceInfo { path, exceptions, crates_and_deps, submodules } in WORKSPACES {
         if has_missing_submodule(root, submodules) {
@@ -672,7 +678,7 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
         }
 
         if !root.join(path).join("Cargo.lock").exists() {
-            tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock");
+            check.error(format!("the `{path}` workspace doesn't have a Cargo.lock"));
             continue;
         }
 
@@ -683,16 +689,23 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
             .other_options(vec!["--locked".to_owned()]);
         let metadata = t!(cmd.exec());
 
-        check_license_exceptions(&metadata, path, exceptions, bad);
+        check_license_exceptions(&metadata, path, exceptions, &mut check);
         if let Some((crates, permitted_deps, location)) = crates_and_deps {
             let descr = crates.get(0).unwrap_or(&path);
-            check_permitted_dependencies(&metadata, descr, permitted_deps, crates, location, bad);
+            check_permitted_dependencies(
+                &metadata,
+                descr,
+                permitted_deps,
+                crates,
+                location,
+                &mut check,
+            );
         }
 
         if path == "library" {
-            check_runtime_license_exceptions(&metadata, bad);
-            check_runtime_no_duplicate_dependencies(&metadata, bad);
-            check_runtime_no_proc_macros(&metadata, bad);
+            check_runtime_license_exceptions(&metadata, &mut check);
+            check_runtime_no_duplicate_dependencies(&metadata, &mut check);
+            check_runtime_no_proc_macros(&metadata, &mut check);
             checked_runtime_licenses = true;
         }
     }
@@ -703,7 +716,7 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
 }
 
 /// Ensure the list of proc-macro crate transitive dependencies is up to date
-fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
+fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, check: &mut RunningCheck) {
     let mut cmd = cargo_metadata::MetadataCommand::new();
     cmd.cargo_path(cargo)
         .manifest_path(root.join("Cargo.toml"))
@@ -750,22 +763,22 @@ pub static CRATES: &[&str] = &[
         )
         .unwrap();
     } else {
-        let old_bad = *bad;
+        let mut error_found = false;
 
         for missing in proc_macro_deps.difference(&expected) {
-            tidy_error!(
-                bad,
+            error_found = true;
+            check.error(format!(
                 "proc-macro crate dependency `{missing}` is not registered in `src/bootstrap/src/utils/proc_macro_deps.rs`",
-            );
+            ));
         }
         for extra in expected.difference(&proc_macro_deps) {
-            tidy_error!(
-                bad,
+            error_found = true;
+            check.error(format!(
                 "`{extra}` is registered in `src/bootstrap/src/utils/proc_macro_deps.rs`, but is not a proc-macro crate dependency",
-            );
+            ));
         }
-        if *bad != old_bad {
-            eprintln!("Run `./x.py test tidy --bless` to regenerate the list");
+        if error_found {
+            check.message("Run `./x.py test tidy --bless` to regenerate the list");
         }
     }
 }
@@ -787,7 +800,7 @@ pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool {
 ///
 /// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole
 /// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx.
-fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
+fn check_runtime_license_exceptions(metadata: &Metadata, check: &mut RunningCheck) {
     for pkg in &metadata.packages {
         if pkg.source.is_none() {
             // No need to check local packages.
@@ -796,7 +809,8 @@ fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
         let license = match &pkg.license {
             Some(license) => license,
             None => {
-                tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id);
+                check
+                    .error(format!("dependency `{}` does not define a license expression", pkg.id));
                 continue;
             }
         };
@@ -809,7 +823,7 @@ fn check_runtime_license_exceptions(metadata: &Metadata, bad: &mut bool) {
                 continue;
             }
 
-            tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
+            check.error(format!("invalid license `{}` in `{}`", license, pkg.id));
         }
     }
 }
@@ -821,37 +835,32 @@ fn check_license_exceptions(
     metadata: &Metadata,
     workspace: &str,
     exceptions: &[(&str, &str)],
-    bad: &mut bool,
+    check: &mut RunningCheck,
 ) {
     // Validate the EXCEPTIONS list hasn't changed.
     for (name, license) in exceptions {
         // Check that the package actually exists.
         if !metadata.packages.iter().any(|p| *p.name == *name) {
-            tidy_error!(
-                bad,
-                "could not find exception package `{}` in workspace `{workspace}`\n\
+            check.error(format!(
+                "could not find exception package `{name}` in workspace `{workspace}`\n\
                 Remove from EXCEPTIONS list if it is no longer used.",
-                name
-            );
+            ));
         }
         // Check that the license hasn't changed.
         for pkg in metadata.packages.iter().filter(|p| *p.name == *name) {
             match &pkg.license {
                 None => {
-                    tidy_error!(
-                        bad,
+                    check.error(format!(
                         "dependency exception `{}` in workspace `{workspace}` does not declare a license expression",
                         pkg.id
-                    );
+                    ));
                 }
                 Some(pkg_license) => {
                     if pkg_license.as_str() != *license {
-                        println!(
-                            "dependency exception `{name}` license in workspace `{workspace}` has changed"
-                        );
-                        println!("    previously `{license}` now `{pkg_license}`");
-                        println!("    update EXCEPTIONS for the new license");
-                        *bad = true;
+                        check.error(format!(r#"dependency exception `{name}` license in workspace `{workspace}` has changed
+    previously `{license}` now `{pkg_license}`
+    update EXCEPTIONS for the new license
+"#));
                     }
                 }
             }
@@ -872,26 +881,23 @@ fn check_license_exceptions(
         let license = match &pkg.license {
             Some(license) => license,
             None => {
-                tidy_error!(
-                    bad,
+                check.error(format!(
                     "dependency `{}` in workspace `{workspace}` does not define a license expression",
                     pkg.id
-                );
+                ));
                 continue;
             }
         };
         if !LICENSES.contains(&license.as_str()) {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "invalid license `{}` for package `{}` in workspace `{workspace}`",
-                license,
-                pkg.id
-            );
+                license, pkg.id
+            ));
         }
     }
 }
 
-fn check_runtime_no_duplicate_dependencies(metadata: &Metadata, bad: &mut bool) {
+fn check_runtime_no_duplicate_dependencies(metadata: &Metadata, check: &mut RunningCheck) {
     let mut seen_pkgs = HashSet::new();
     for pkg in &metadata.packages {
         if pkg.source.is_none() {
@@ -902,25 +908,23 @@ fn check_runtime_no_duplicate_dependencies(metadata: &Metadata, bad: &mut bool)
         // depends on two version of (one for the `wasm32-wasip1` target and
         // another for the `wasm32-wasip2` target).
         if pkg.name.to_string() != "wasi" && !seen_pkgs.insert(&*pkg.name) {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "duplicate package `{}` is not allowed for the standard library",
                 pkg.name
-            );
+            ));
         }
     }
 }
 
-fn check_runtime_no_proc_macros(metadata: &Metadata, bad: &mut bool) {
+fn check_runtime_no_proc_macros(metadata: &Metadata, check: &mut RunningCheck) {
     for pkg in &metadata.packages {
         if pkg.targets.iter().any(|target| target.is_proc_macro()) {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "proc macro `{}` is not allowed as standard library dependency.\n\
                 Using proc macros in the standard library would break cross-compilation \
                 as proc-macros don't get shipped for the host tuple.",
                 pkg.name
-            );
+            ));
         }
     }
 }
@@ -935,7 +939,7 @@ fn check_permitted_dependencies(
     permitted_dependencies: &[&'static str],
     restricted_dependency_crates: &[&'static str],
     permitted_location: ListLocation,
-    bad: &mut bool,
+    check: &mut RunningCheck,
 ) {
     let mut has_permitted_dep_error = false;
     let mut deps = HashSet::new();
@@ -957,11 +961,10 @@ fn check_permitted_dependencies(
             }
         }
         if !deps.iter().any(|dep_id| compare(pkg_from_id(metadata, dep_id), permitted)) {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "could not find allowed package `{permitted}`\n\
                 Remove from PERMITTED_DEPENDENCIES list if it is no longer used.",
-            );
+            ));
             has_permitted_dep_error = true;
         }
     }
@@ -988,7 +991,7 @@ fn check_permitted_dependencies(
                 false
             };
             if !is_eq {
-                tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
+                check.error(format!("Dependency for {descr} not explicitly permitted: {}", dep.id));
                 has_permitted_dep_error = true;
             }
         }
diff --git a/src/tools/tidy/src/diagnostics.rs b/src/tools/tidy/src/diagnostics.rs
new file mode 100644
index 00000000000..6e95f97d010
--- /dev/null
+++ b/src/tools/tidy/src/diagnostics.rs
@@ -0,0 +1,243 @@
+use std::collections::HashSet;
+use std::fmt::{Display, Formatter};
+use std::path::{Path, PathBuf};
+use std::sync::{Arc, Mutex};
+
+use termcolor::{Color, WriteColor};
+
+/// Collects diagnostics from all tidy steps, and contains shared information
+/// that determines how should message and logs be presented.
+///
+/// Since checks are executed in parallel, the context is internally synchronized, to avoid
+/// all checks to lock it explicitly.
+#[derive(Clone)]
+pub struct DiagCtx(Arc<Mutex<DiagCtxInner>>);
+
+impl DiagCtx {
+    pub fn new(root_path: &Path, verbose: bool) -> Self {
+        Self(Arc::new(Mutex::new(DiagCtxInner {
+            running_checks: Default::default(),
+            finished_checks: Default::default(),
+            root_path: root_path.to_path_buf(),
+            verbose,
+        })))
+    }
+
+    pub fn start_check<Id: Into<CheckId>>(&self, id: Id) -> RunningCheck {
+        let mut id = id.into();
+
+        let mut ctx = self.0.lock().unwrap();
+
+        // Shorten path for shorter diagnostics
+        id.path = match id.path {
+            Some(path) => Some(path.strip_prefix(&ctx.root_path).unwrap_or(&path).to_path_buf()),
+            None => None,
+        };
+
+        ctx.start_check(id.clone());
+        RunningCheck {
+            id,
+            bad: false,
+            ctx: self.0.clone(),
+            #[cfg(test)]
+            errors: vec![],
+        }
+    }
+
+    pub fn into_failed_checks(self) -> Vec<FinishedCheck> {
+        let ctx = Arc::into_inner(self.0).unwrap().into_inner().unwrap();
+        assert!(ctx.running_checks.is_empty(), "Some checks are still running");
+        ctx.finished_checks.into_iter().filter(|c| c.bad).collect()
+    }
+}
+
+struct DiagCtxInner {
+    running_checks: HashSet<CheckId>,
+    finished_checks: HashSet<FinishedCheck>,
+    verbose: bool,
+    root_path: PathBuf,
+}
+
+impl DiagCtxInner {
+    fn start_check(&mut self, id: CheckId) {
+        if self.has_check_id(&id) {
+            panic!("Starting a check named `{id:?}` for the second time");
+        }
+
+        self.running_checks.insert(id);
+    }
+
+    fn finish_check(&mut self, check: FinishedCheck) {
+        assert!(
+            self.running_checks.remove(&check.id),
+            "Finishing check `{:?}` that was not started",
+            check.id
+        );
+
+        if check.bad {
+            output_message("FAIL", Some(&check.id), Some(COLOR_ERROR));
+        } else if self.verbose {
+            output_message("OK", Some(&check.id), Some(COLOR_SUCCESS));
+        }
+
+        self.finished_checks.insert(check);
+    }
+
+    fn has_check_id(&self, id: &CheckId) -> bool {
+        self.running_checks
+            .iter()
+            .chain(self.finished_checks.iter().map(|c| &c.id))
+            .any(|c| c == id)
+    }
+}
+
+/// Identifies a single step
+#[derive(PartialEq, Eq, Hash, Clone, Debug)]
+pub struct CheckId {
+    pub name: String,
+    pub path: Option<PathBuf>,
+}
+
+impl CheckId {
+    pub fn new(name: &'static str) -> Self {
+        Self { name: name.to_string(), path: None }
+    }
+
+    pub fn path(self, path: &Path) -> Self {
+        Self { path: Some(path.to_path_buf()), ..self }
+    }
+}
+
+impl From<&'static str> for CheckId {
+    fn from(name: &'static str) -> Self {
+        Self::new(name)
+    }
+}
+
+impl Display for CheckId {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.name)?;
+        if let Some(path) = &self.path {
+            write!(f, " ({})", path.display())?;
+        }
+        Ok(())
+    }
+}
+
+#[derive(PartialEq, Eq, Hash, Debug)]
+pub struct FinishedCheck {
+    id: CheckId,
+    bad: bool,
+}
+
+impl FinishedCheck {
+    pub fn id(&self) -> &CheckId {
+        &self.id
+    }
+}
+
+/// Represents a single tidy check, identified by its `name`, running.
+pub struct RunningCheck {
+    id: CheckId,
+    bad: bool,
+    ctx: Arc<Mutex<DiagCtxInner>>,
+    #[cfg(test)]
+    errors: Vec<String>,
+}
+
+impl RunningCheck {
+    /// Creates a new instance of a running check without going through the diag
+    /// context.
+    /// Useful if you want to run some functions from tidy without configuring
+    /// diagnostics.
+    pub fn new_noop() -> Self {
+        let ctx = DiagCtx::new(Path::new(""), false);
+        ctx.start_check("noop")
+    }
+
+    /// Immediately output an error and mark the check as failed.
+    pub fn error<T: Display>(&mut self, msg: T) {
+        self.mark_as_bad();
+        let msg = msg.to_string();
+        output_message(&msg, Some(&self.id), Some(COLOR_ERROR));
+        #[cfg(test)]
+        self.errors.push(msg);
+    }
+
+    /// Immediately output a warning.
+    pub fn warning<T: Display>(&mut self, msg: T) {
+        output_message(&msg.to_string(), Some(&self.id), Some(COLOR_WARNING));
+    }
+
+    /// Output an informational message
+    pub fn message<T: Display>(&mut self, msg: T) {
+        output_message(&msg.to_string(), Some(&self.id), None);
+    }
+
+    /// Output a message only if verbose output is enabled.
+    pub fn verbose_msg<T: Display>(&mut self, msg: T) {
+        if self.is_verbose_enabled() {
+            self.message(msg);
+        }
+    }
+
+    /// Has an error already occured for this check?
+    pub fn is_bad(&self) -> bool {
+        self.bad
+    }
+
+    /// Is verbose output enabled?
+    pub fn is_verbose_enabled(&self) -> bool {
+        self.ctx.lock().unwrap().verbose
+    }
+
+    #[cfg(test)]
+    pub fn get_errors(&self) -> Vec<String> {
+        self.errors.clone()
+    }
+
+    fn mark_as_bad(&mut self) {
+        self.bad = true;
+    }
+}
+
+impl Drop for RunningCheck {
+    fn drop(&mut self) {
+        self.ctx.lock().unwrap().finish_check(FinishedCheck { id: self.id.clone(), bad: self.bad })
+    }
+}
+
+pub const COLOR_SUCCESS: Color = Color::Green;
+pub const COLOR_ERROR: Color = Color::Red;
+pub const COLOR_WARNING: Color = Color::Yellow;
+
+/// Output a message to stderr.
+/// The message can be optionally scoped to a certain check, and it can also have a certain color.
+pub fn output_message(msg: &str, id: Option<&CheckId>, color: Option<Color>) {
+    use std::io::Write;
+
+    use termcolor::{ColorChoice, ColorSpec, StandardStream};
+
+    let mut stderr = StandardStream::stderr(ColorChoice::Auto);
+    if let Some(color) = &color {
+        stderr.set_color(ColorSpec::new().set_fg(Some(*color))).unwrap();
+    }
+
+    match id {
+        Some(id) => {
+            write!(&mut stderr, "tidy [{}", id.name).unwrap();
+            if let Some(path) = &id.path {
+                write!(&mut stderr, " ({})", path.display()).unwrap();
+            }
+            write!(&mut stderr, "]").unwrap();
+        }
+        None => {
+            write!(&mut stderr, "tidy").unwrap();
+        }
+    }
+    if color.is_some() {
+        stderr.set_color(&ColorSpec::new()).unwrap();
+    }
+
+    writeln!(&mut stderr, ": {msg}").unwrap();
+}
diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs
index 08f6a3909f8..448e0b0e0a8 100644
--- a/src/tools/tidy/src/edition.rs
+++ b/src/tools/tidy/src/edition.rs
@@ -2,9 +2,11 @@
 
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::walk::{filter_dirs, walk};
 
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("edition").path(path));
     walk(path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap();
@@ -23,11 +25,10 @@ pub fn check(path: &Path, bad: &mut bool) {
         // Check that all packages use the 2021 edition. Virtual workspaces don't allow setting an
         // edition, so these shouldn't be checked.
         if is_package && !is_current_edition {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "{} doesn't have `edition = \"2021\"` or `edition = \"2024\"` on a separate line",
                 file.display()
-            );
+            ));
         }
     });
 }
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index 65aa89fe801..83fbefa43d9 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -22,6 +22,7 @@ use std::path::Path;
 
 use regex::Regex;
 
+use crate::diagnostics::{DiagCtx, RunningCheck};
 use crate::walk::{filter_dirs, walk, walk_many};
 
 const ERROR_CODES_PATH: &str = "compiler/rustc_error_codes/src/lib.rs";
@@ -35,71 +36,50 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E07
 const IGNORE_UI_TEST_CHECK: &[&str] =
     &["E0461", "E0465", "E0514", "E0554", "E0640", "E0717", "E0729"];
 
-macro_rules! verbose_print {
-    ($verbose:expr, $($fmt:tt)*) => {
-        if $verbose {
-            println!("{}", format_args!($($fmt)*));
-        }
-    };
-}
-
-pub fn check(
-    root_path: &Path,
-    search_paths: &[&Path],
-    verbose: bool,
-    ci_info: &crate::CiInfo,
-    bad: &mut bool,
-) {
-    let mut errors = Vec::new();
+pub fn check(root_path: &Path, search_paths: &[&Path], ci_info: &crate::CiInfo, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("error_codes");
 
     // Check that no error code explanation was removed.
-    check_removed_error_code_explanation(ci_info, bad);
+    check_removed_error_code_explanation(ci_info, &mut check);
 
     // Stage 1: create list
-    let error_codes = extract_error_codes(root_path, &mut errors);
-    if verbose {
-        println!("Found {} error codes", error_codes.len());
-        println!("Highest error code: `{}`", error_codes.iter().max().unwrap());
-    }
+    let error_codes = extract_error_codes(root_path, &mut check);
+    check.verbose_msg(format!("Found {} error codes", error_codes.len()));
+    check.verbose_msg(format!("Highest error code: `{}`", error_codes.iter().max().unwrap()));
 
     // Stage 2: check list has docs
-    let no_longer_emitted = check_error_codes_docs(root_path, &error_codes, &mut errors, verbose);
+    let no_longer_emitted = check_error_codes_docs(root_path, &error_codes, &mut check);
 
     // Stage 3: check list has UI tests
-    check_error_codes_tests(root_path, &error_codes, &mut errors, verbose, &no_longer_emitted);
+    check_error_codes_tests(root_path, &error_codes, &mut check, &no_longer_emitted);
 
     // Stage 4: check list is emitted by compiler
-    check_error_codes_used(search_paths, &error_codes, &mut errors, &no_longer_emitted, verbose);
-
-    // Print any errors.
-    for error in errors {
-        tidy_error!(bad, "{}", error);
-    }
+    check_error_codes_used(search_paths, &error_codes, &mut check, &no_longer_emitted);
 }
 
-fn check_removed_error_code_explanation(ci_info: &crate::CiInfo, bad: &mut bool) {
+fn check_removed_error_code_explanation(ci_info: &crate::CiInfo, check: &mut RunningCheck) {
     let Some(base_commit) = &ci_info.base_commit else {
-        eprintln!("Skipping error code explanation removal check");
+        check.verbose_msg("Skipping error code explanation removal check");
         return;
     };
     let Some(diff) = crate::git_diff(base_commit, "--name-status") else {
-        *bad = true;
-        eprintln!("removed error code explanation tidy check: Failed to run git diff");
+        check.error(format!("removed error code explanation: Failed to run git diff"));
         return;
     };
     if diff.lines().any(|line| {
         line.starts_with('D') && line.contains("compiler/rustc_error_codes/src/error_codes/")
     }) {
-        *bad = true;
-        eprintln!("tidy check error: Error code explanations should never be removed!");
-        eprintln!("Take a look at E0001 to see how to handle it.");
+        check.error(format!(
+            r#"Error code explanations should never be removed!
+Take a look at E0001 to see how to handle it."#
+        ));
         return;
     }
-    println!("No error code explanation was removed!");
+    check.verbose_msg("No error code explanation was removed!");
 }
 
 /// Stage 1: Parses a list of error codes from `error_codes.rs`.
-fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String> {
+fn extract_error_codes(root_path: &Path, check: &mut RunningCheck) -> Vec<String> {
     let path = root_path.join(Path::new(ERROR_CODES_PATH));
     let file =
         fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}"));
@@ -117,7 +97,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
             // Extract the error code from the line. Emit a fatal error if it is not in the correct
             // format.
             let Some(split_line) = split_line else {
-                errors.push(format!(
+                check.error(format!(
                     "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
                     but got \"{line}\" without a `:` delimiter",
                 ));
@@ -128,8 +108,9 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
 
             // If this is a duplicate of another error code, emit a fatal error.
             if error_codes.contains(&err_code) {
-                errors
-                    .push(format!("{path}:{line_index}: Found duplicate error code: `{err_code}`"));
+                check.error(format!(
+                    "{path}:{line_index}: Found duplicate error code: `{err_code}`"
+                ));
                 continue;
             }
 
@@ -140,14 +121,14 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
             // Ensure that the line references the correct markdown file.
             let rest = split_line.1.split_once(',');
             let Some(rest) = rest else {
-                errors.push(format!(
+                check.error(format!(
                     "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
                     but got \"{line}\" without a `,` delimiter",
                 ));
                 continue;
             };
             if error_num_as_str != rest.0.trim() {
-                errors.push(format!(
+                check.error(format!(
                     "{path}:{line_index}: `{}:` should be followed by `{},` but instead found `{}` in \
                     `compiler/rustc_error_codes/src/lib.rs`",
                     err_code,
@@ -157,7 +138,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
                 continue;
             }
             if !rest.1.trim().is_empty() && !rest.1.trim().starts_with("//") {
-                errors.push(format!("{path}:{line_index}: should only have one error per line"));
+                check.error(format!("{path}:{line_index}: should only have one error per line"));
                 continue;
             }
 
@@ -172,8 +153,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
 fn check_error_codes_docs(
     root_path: &Path,
     error_codes: &[String],
-    errors: &mut Vec<String>,
-    verbose: bool,
+    check: &mut RunningCheck,
 ) -> Vec<String> {
     let docs_path = root_path.join(Path::new(ERROR_DOCS_PATH));
 
@@ -184,7 +164,7 @@ fn check_error_codes_docs(
 
         // Error if the file isn't markdown.
         if path.extension() != Some(OsStr::new("md")) {
-            errors.push(format!(
+            check.error(format!(
                 "Found unexpected non-markdown file in error code docs directory: {}",
                 path.display()
             ));
@@ -196,7 +176,7 @@ fn check_error_codes_docs(
         let err_code = filename.unwrap().0; // `unwrap` is ok because we know the filename is in the correct format.
 
         if error_codes.iter().all(|e| e != err_code) {
-            errors.push(format!(
+            check.error(format!(
                 "Found valid file `{}` in error code docs directory without corresponding \
                 entry in `rustc_error_codes/src/lib.rs`",
                 path.display()
@@ -208,11 +188,10 @@ fn check_error_codes_docs(
             check_explanation_has_doctest(contents, err_code);
 
         if emit_ignore_warning {
-            verbose_print!(
-                verbose,
+            check.verbose_msg(format!(
                 "warning: Error code `{err_code}` uses the ignore header. This should not be used, add the error code to the \
                 `IGNORE_DOCTEST_CHECK` constant instead."
-            );
+            ));
         }
 
         if no_longer_emitted {
@@ -220,11 +199,10 @@ fn check_error_codes_docs(
         }
 
         if !found_code_example {
-            verbose_print!(
-                verbose,
+            check.verbose_msg(format!(
                 "warning: Error code `{err_code}` doesn't have a code example, all error codes are expected to have one \
                 (even if untested)."
-            );
+            ));
             return;
         }
 
@@ -232,12 +210,12 @@ fn check_error_codes_docs(
 
         // Check that the explanation has a doctest, and if it shouldn't, that it doesn't
         if !found_proper_doctest && !test_ignored {
-            errors.push(format!(
+            check.error(format!(
                 "`{}` doesn't use its own error code in compile_fail example",
                 path.display(),
             ));
         } else if found_proper_doctest && test_ignored {
-            errors.push(format!(
+            check.error(format!(
                 "`{}` has a compile_fail doctest with its own error code, it shouldn't \
                 be listed in `IGNORE_DOCTEST_CHECK`",
                 path.display(),
@@ -289,8 +267,7 @@ fn check_explanation_has_doctest(explanation: &str, err_code: &str) -> (bool, bo
 fn check_error_codes_tests(
     root_path: &Path,
     error_codes: &[String],
-    errors: &mut Vec<String>,
-    verbose: bool,
+    check: &mut RunningCheck,
     no_longer_emitted: &[String],
 ) {
     let tests_path = root_path.join(Path::new(ERROR_TESTS_PATH));
@@ -299,15 +276,14 @@ fn check_error_codes_tests(
         let test_path = tests_path.join(format!("{code}.stderr"));
 
         if !test_path.exists() && !IGNORE_UI_TEST_CHECK.contains(&code.as_str()) {
-            verbose_print!(
-                verbose,
+            check.verbose_msg(format!(
                 "warning: Error code `{code}` needs to have at least one UI test in the `tests/error-codes/` directory`!"
-            );
+            ));
             continue;
         }
         if IGNORE_UI_TEST_CHECK.contains(&code.as_str()) {
             if test_path.exists() {
-                errors.push(format!(
+                check.error(format!(
                     "Error code `{code}` has a UI test in `tests/ui/error-codes/{code}.rs`, it shouldn't be listed in `EXEMPTED_FROM_TEST`!"
                 ));
             }
@@ -317,11 +293,10 @@ fn check_error_codes_tests(
         let file = match fs::read_to_string(&test_path) {
             Ok(file) => file,
             Err(err) => {
-                verbose_print!(
-                    verbose,
+                check.verbose_msg(format!(
                     "warning: Failed to read UI test file (`{}`) for `{code}` but the file exists. The test is assumed to work:\n{err}",
                     test_path.display()
-                );
+                ));
                 continue;
             }
         };
@@ -343,10 +318,9 @@ fn check_error_codes_tests(
         }
 
         if !found_code {
-            verbose_print!(
-                verbose,
+            check.verbose_msg(format!(
                 "warning: Error code `{code}` has a UI test file, but doesn't contain its own error code!"
-            );
+            ));
         }
     }
 }
@@ -355,9 +329,8 @@ fn check_error_codes_tests(
 fn check_error_codes_used(
     search_paths: &[&Path],
     error_codes: &[String],
-    errors: &mut Vec<String>,
+    check: &mut RunningCheck,
     no_longer_emitted: &[String],
-    verbose: bool,
 ) {
     // Search for error codes in the form `E0123`.
     let regex = Regex::new(r#"\bE\d{4}\b"#).unwrap();
@@ -384,7 +357,7 @@ fn check_error_codes_used(
 
                     if !error_codes.contains(&error_code) {
                         // This error code isn't properly defined, we must error.
-                        errors.push(format!("Error code `{error_code}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/lib.rs`."));
+                        check.error(format!("Error code `{error_code}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/lib.rs`."));
                         continue;
                     }
 
@@ -397,7 +370,7 @@ fn check_error_codes_used(
 
     for code in error_codes {
         if !found_codes.contains(code) && !no_longer_emitted.contains(code) {
-            errors.push(format!(
+            check.error(format!(
                 "Error code `{code}` exists, but is not emitted by the compiler!\n\
                 Please mark the code as no longer emitted by adding the following note to the top of the `EXXXX.md` file:\n\
                 `#### Note: this error code is no longer emitted by the compiler`\n\
@@ -406,10 +379,9 @@ fn check_error_codes_used(
         }
 
         if found_codes.contains(code) && no_longer_emitted.contains(code) {
-            verbose_print!(
-                verbose,
+            check.verbose_msg(format!(
                 "warning: Error code `{code}` is used when it's marked as \"no longer emitted\""
-            );
+            ));
         }
     }
 }
diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs
index 2b212cfa67a..f75de13b45c 100644
--- a/src/tools/tidy/src/extdeps.rs
+++ b/src/tools/tidy/src/extdeps.rs
@@ -4,6 +4,7 @@ use std::fs;
 use std::path::Path;
 
 use crate::deps::WorkspaceInfo;
+use crate::diagnostics::DiagCtx;
 
 /// List of allowed sources for packages.
 const ALLOWED_SOURCES: &[&str] = &[
@@ -14,7 +15,9 @@ const ALLOWED_SOURCES: &[&str] = &[
 
 /// Checks for external package sources. `root` is the path to the directory that contains the
 /// workspace `Cargo.toml`.
-pub fn check(root: &Path, bad: &mut bool) {
+pub fn check(root: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("extdeps");
+
     for &WorkspaceInfo { path, submodules, .. } in crate::deps::WORKSPACES {
         if crate::deps::has_missing_submodule(root, submodules) {
             continue;
@@ -25,7 +28,7 @@ pub fn check(root: &Path, bad: &mut bool) {
         let lockfile = root.join(path).join("Cargo.lock");
 
         if !lockfile.exists() {
-            tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock");
+            check.error(format!("the `{path}` workspace doesn't have a Cargo.lock"));
             continue;
         }
 
@@ -44,7 +47,7 @@ pub fn check(root: &Path, bad: &mut bool) {
 
             // Ensure source is allowed.
             if !ALLOWED_SOURCES.contains(&source) {
-                tidy_error!(bad, "invalid source: {}", source);
+                check.error(format!("invalid source: {}", source));
             }
         }
     }
diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs
index a6b50b5ca47..9f2f2da2e86 100644
--- a/src/tools/tidy/src/extra_checks/mod.rs
+++ b/src/tools/tidy/src/extra_checks/mod.rs
@@ -24,6 +24,7 @@ use std::str::FromStr;
 use std::{fmt, fs, io};
 
 use crate::CiInfo;
+use crate::diagnostics::DiagCtx;
 
 mod rustdoc_js;
 
@@ -54,8 +55,10 @@ pub fn check(
     bless: bool,
     extra_checks: Option<&str>,
     pos_args: &[String],
-    bad: &mut bool,
+    diag_ctx: DiagCtx,
 ) {
+    let mut check = diag_ctx.start_check("extra_checks");
+
     if let Err(e) = check_impl(
         root_path,
         outdir,
@@ -68,7 +71,7 @@ pub fn check(
         extra_checks,
         pos_args,
     ) {
-        tidy_error!(bad, "{e}");
+        check.error(e);
     }
 }
 
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 6618ba24be6..0a0ba217c63 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -16,6 +16,7 @@ use std::num::NonZeroU32;
 use std::path::{Path, PathBuf};
 use std::{fmt, fs};
 
+use crate::diagnostics::{DiagCtx, RunningCheck};
 use crate::walk::{filter_dirs, filter_not_rust, walk, walk_many};
 
 #[cfg(test)]
@@ -91,13 +92,14 @@ pub fn check(
     tests_path: &Path,
     compiler_path: &Path,
     lib_path: &Path,
-    bad: &mut bool,
-    verbose: bool,
+    diag_ctx: DiagCtx,
 ) -> CollectedFeatures {
-    let mut features = collect_lang_features(compiler_path, bad);
+    let mut check = diag_ctx.start_check("features");
+
+    let mut features = collect_lang_features(compiler_path, &mut check);
     assert!(!features.is_empty());
 
-    let lib_features = get_and_check_lib_features(lib_path, bad, &features);
+    let lib_features = get_and_check_lib_features(lib_path, &mut check, &features);
     assert!(!lib_features.is_empty());
 
     walk_many(
@@ -121,7 +123,7 @@ pub fn check(
 
             for (i, line) in contents.lines().enumerate() {
                 let mut err = |msg: &str| {
-                    tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
+                    check.error(format!("{}:{}: {}", file.display(), i + 1, msg));
                 };
 
                 let gate_test_str = "gate-test-";
@@ -175,7 +177,7 @@ pub fn check(
     }
 
     if !gate_untested.is_empty() {
-        tidy_error!(bad, "Found {} features without a gate test.", gate_untested.len());
+        check.error(format!("Found {} features without a gate test.", gate_untested.len()));
     }
 
     let (version, channel) = get_version_and_channel(src_path);
@@ -189,39 +191,32 @@ pub fn check(
         let file = feature.file.display();
         let line = feature.line;
         if since > version && since != Version::CurrentPlaceholder {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is newer than the current {version}"
-            );
+            ));
         }
         if channel == "nightly" && since == version {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "{file}:{line}: The stabilization version {since} of {kind} feature `{feature_name}` is written out but should be {}",
                 version::VERSION_PLACEHOLDER
-            );
+            ));
         }
         if channel != "nightly" && since == Version::CurrentPlaceholder {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "{file}:{line}: The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel",
-            );
+            ));
         }
     }
 
-    if *bad {
-        return CollectedFeatures { lib: lib_features, lang: features };
-    }
-
-    if verbose {
+    if !check.is_bad() && check.is_verbose_enabled() {
         let mut lines = Vec::new();
         lines.extend(format_features(&features, "lang"));
         lines.extend(format_features(&lib_features, "lib"));
-
         lines.sort();
-        for line in lines {
-            println!("* {line}");
-        }
+
+        check.verbose_msg(
+            lines.into_iter().map(|l| format!("* {l}")).collect::<Vec<String>>().join("\n"),
+        );
     }
 
     CollectedFeatures { lib: lib_features, lang: features }
@@ -275,15 +270,20 @@ fn test_filen_gate<'f>(filen_underscore: &'f str, features: &mut Features) -> Op
     None
 }
 
-pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features {
+pub fn collect_lang_features(base_compiler_path: &Path, check: &mut RunningCheck) -> Features {
     let mut features = Features::new();
-    collect_lang_features_in(&mut features, base_compiler_path, "accepted.rs", bad);
-    collect_lang_features_in(&mut features, base_compiler_path, "removed.rs", bad);
-    collect_lang_features_in(&mut features, base_compiler_path, "unstable.rs", bad);
+    collect_lang_features_in(&mut features, base_compiler_path, "accepted.rs", check);
+    collect_lang_features_in(&mut features, base_compiler_path, "removed.rs", check);
+    collect_lang_features_in(&mut features, base_compiler_path, "unstable.rs", check);
     features
 }
 
-fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, bad: &mut bool) {
+fn collect_lang_features_in(
+    features: &mut Features,
+    base: &Path,
+    file: &str,
+    check: &mut RunningCheck,
+) {
     let path = base.join("rustc_feature").join("src").join(file);
     let contents = t!(fs::read_to_string(&path));
 
@@ -315,13 +315,11 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
 
         if line.starts_with(FEATURE_GROUP_START_PREFIX) {
             if in_feature_group {
-                tidy_error!(
-                    bad,
-                    "{}:{}: \
+                check.error(format!(
+                    "{}:{line_number}: \
                         new feature group is started without ending the previous one",
-                    path.display(),
-                    line_number,
-                );
+                    path.display()
+                ));
             }
 
             in_feature_group = true;
@@ -353,14 +351,10 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
         let since = match since_str.parse() {
             Ok(since) => Some(since),
             Err(err) => {
-                tidy_error!(
-                    bad,
-                    "{}:{}: failed to parse since: {} ({:?})",
-                    path.display(),
-                    line_number,
-                    since_str,
-                    err,
-                );
+                check.error(format!(
+                    "{}:{line_number}: failed to parse since: {since_str} ({err:?})",
+                    path.display()
+                ));
                 None
             }
         };
@@ -371,13 +365,10 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
                 let correct_index = match prev_names.binary_search(&name) {
                     Ok(_) => {
                         // This only occurs when the feature name has already been declared.
-                        tidy_error!(
-                            bad,
-                            "{}:{}: duplicate feature {}",
-                            path.display(),
-                            line_number,
-                            name,
-                        );
+                        check.error(format!(
+                            "{}:{line_number}: duplicate feature {name}",
+                            path.display()
+                        ));
                         // skip any additional checks for this line
                         continue;
                     }
@@ -398,14 +389,10 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
                     )
                 };
 
-                tidy_error!(
-                    bad,
-                    "{}:{}: feature {} is not sorted by feature name (should be {})",
+                check.error(format!(
+                    "{}:{line_number}: feature {name} is not sorted by feature name (should be {correct_placement})",
                     path.display(),
-                    line_number,
-                    name,
-                    correct_placement,
-                );
+                ));
             }
             prev_names.push(name);
         }
@@ -413,13 +400,10 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
         let issue_str = parts.next().unwrap().trim();
         let tracking_issue = if issue_str.starts_with("None") {
             if level == Status::Unstable && !next_feature_omits_tracking_issue {
-                tidy_error!(
-                    bad,
-                    "{}:{}: no tracking issue for feature {}",
+                check.error(format!(
+                    "{}:{line_number}: no tracking issue for feature {name}",
                     path.display(),
-                    line_number,
-                    name,
-                );
+                ));
             }
             None
         } else {
@@ -428,13 +412,11 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
         };
         match features.entry(name.to_owned()) {
             Entry::Occupied(e) => {
-                tidy_error!(
-                    bad,
-                    "{}:{} feature {name} already specified with status '{}'",
+                check.error(format!(
+                    "{}:{line_number} feature {name} already specified with status '{}'",
                     path.display(),
-                    line_number,
                     e.get().level,
-                );
+                ));
             }
             Entry::Vacant(e) => {
                 e.insert(Feature {
@@ -458,7 +440,7 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
 
 fn get_and_check_lib_features(
     base_src_path: &Path,
-    bad: &mut bool,
+    check: &mut RunningCheck,
     lang_features: &Features,
 ) -> Features {
     let mut lib_features = Features::new();
@@ -469,16 +451,12 @@ fn get_and_check_lib_features(
                     && f.tracking_issue != s.tracking_issue
                     && f.level != Status::Accepted
                 {
-                    tidy_error!(
-                        bad,
-                        "{}:{}: feature gate {} has inconsistent `issue`: \"{}\" mismatches the {} `issue` of \"{}\"",
+                    check.error(format!(
+                        "{}:{line}: feature gate {name} has inconsistent `issue`: \"{}\" mismatches the {display} `issue` of \"{}\"",
                         file.display(),
-                        line,
-                        name,
                         f.tracking_issue_display(),
-                        display,
                         s.tracking_issue_display(),
-                    );
+                    ));
                 }
             };
             check_features(&f, lang_features, "corresponding lang feature");
@@ -486,7 +464,7 @@ fn get_and_check_lib_features(
             lib_features.insert(name.to_owned(), f);
         }
         Err(msg) => {
-            tidy_error!(bad, "{}:{}: {}", file.display(), line, msg);
+            check.error(format!("{}:{line}: {msg}", file.display()));
         }
     });
     lib_features
diff --git a/src/tools/tidy/src/filenames.rs b/src/tools/tidy/src/filenames.rs
index 53115f4eaa4..835cbefbf69 100644
--- a/src/tools/tidy/src/filenames.rs
+++ b/src/tools/tidy/src/filenames.rs
@@ -10,7 +10,10 @@
 use std::path::Path;
 use std::process::Command;
 
-pub fn check(root_path: &Path, bad: &mut bool) {
+use crate::diagnostics::DiagCtx;
+
+pub fn check(root_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("filenames");
     let stat_output = Command::new("git")
         .arg("-C")
         .arg(root_path)
@@ -20,20 +23,17 @@ pub fn check(root_path: &Path, bad: &mut bool) {
         .stdout;
     for filename in stat_output.split(|&b| b == 0) {
         match str::from_utf8(filename) {
-            Err(_) => tidy_error!(
-                bad,
+            Err(_) => check.error(format!(
                 r#"non-UTF8 file names are not supported: "{}""#,
                 String::from_utf8_lossy(filename),
-            ),
-            Ok(name) if name.chars().any(|c| c.is_control()) => tidy_error!(
-                bad,
+            )),
+            Ok(name) if name.chars().any(|c| c.is_control()) => check.error(format!(
                 r#"control characters are not supported in file names: "{}""#,
                 String::from_utf8_lossy(filename),
-            ),
-            Ok(name) if name.contains(':') => tidy_error!(
-                bad,
+            )),
+            Ok(name) if name.contains(':') => check.error(format!(
                 r#"":" is not supported in file names because of Windows compatibility: "{name}""#,
-            ),
+            )),
             _ => (),
         }
     }
diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs
index 48d14a37514..02b914c21ae 100644
--- a/src/tools/tidy/src/fluent_alphabetical.rs
+++ b/src/tools/tidy/src/fluent_alphabetical.rs
@@ -7,6 +7,7 @@ use std::path::Path;
 
 use regex::Regex;
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
 use crate::walk::{filter_dirs, walk};
 
 fn message() -> &'static Regex {
@@ -20,19 +21,17 @@ fn is_fluent(path: &Path) -> bool {
 fn check_alphabetic(
     filename: &str,
     fluent: &str,
-    bad: &mut bool,
+    check: &mut RunningCheck,
     all_defined_msgs: &mut HashMap<String, String>,
 ) {
     let mut matches = message().captures_iter(fluent).peekable();
     while let Some(m) = matches.next() {
         let name = m.get(1).unwrap();
         if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
-            tidy_error!(
-                bad,
-                "{filename}: message `{}` is already defined in {}",
+            check.error(format!(
+                "{filename}: message `{}` is already defined in {defined_filename}",
                 name.as_str(),
-                defined_filename,
-            );
+            ));
         }
 
         all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned());
@@ -40,13 +39,12 @@ fn check_alphabetic(
         if let Some(next) = matches.peek() {
             let next = next.get(1).unwrap();
             if name.as_str() > next.as_str() {
-                tidy_error!(
-                    bad,
+                check.error(format!(
                     "{filename}: message `{}` appears before `{}`, but is alphabetically later than it
 run `./x.py test tidy --bless` to sort the file correctly",
                     name.as_str(),
                     next.as_str()
-                );
+                ));
             }
         } else {
             break;
@@ -57,7 +55,7 @@ run `./x.py test tidy --bless` to sort the file correctly",
 fn sort_messages(
     filename: &str,
     fluent: &str,
-    bad: &mut bool,
+    check: &mut RunningCheck,
     all_defined_msgs: &mut HashMap<String, String>,
 ) -> String {
     let mut chunks = vec![];
@@ -65,12 +63,10 @@ fn sort_messages(
     for line in fluent.lines() {
         if let Some(name) = message().find(line) {
             if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) {
-                tidy_error!(
-                    bad,
-                    "{filename}: message `{}` is already defined in {}",
+                check.error(format!(
+                    "{filename}: message `{}` is already defined in {defined_filename}",
                     name.as_str(),
-                    defined_filename,
-                );
+                ));
             }
 
             all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned());
@@ -88,7 +84,9 @@ fn sort_messages(
     out
 }
 
-pub fn check(path: &Path, bless: bool, bad: &mut bool) {
+pub fn check(path: &Path, bless: bool, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("fluent_alphabetical").path(path));
+
     let mut all_defined_msgs = HashMap::new();
     walk(
         path,
@@ -98,7 +96,7 @@ pub fn check(path: &Path, bless: bool, bad: &mut bool) {
                 let sorted = sort_messages(
                     ent.path().to_str().unwrap(),
                     contents,
-                    bad,
+                    &mut check,
                     &mut all_defined_msgs,
                 );
                 if sorted != contents {
@@ -110,12 +108,12 @@ pub fn check(path: &Path, bless: bool, bad: &mut bool) {
                 check_alphabetic(
                     ent.path().to_str().unwrap(),
                     contents,
-                    bad,
+                    &mut check,
                     &mut all_defined_msgs,
                 );
             }
         },
     );
 
-    crate::fluent_used::check(path, all_defined_msgs, bad);
+    crate::fluent_used::check(path, all_defined_msgs, diag_ctx);
 }
diff --git a/src/tools/tidy/src/fluent_lowercase.rs b/src/tools/tidy/src/fluent_lowercase.rs
index 13f0319909e..1d80fda8f3b 100644
--- a/src/tools/tidy/src/fluent_lowercase.rs
+++ b/src/tools/tidy/src/fluent_lowercase.rs
@@ -4,6 +4,7 @@ use std::path::Path;
 
 use fluent_syntax::ast::{Entry, Message, PatternElement};
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
 use crate::walk::{filter_dirs, walk};
 
 #[rustfmt::skip]
@@ -34,7 +35,7 @@ fn is_allowed_capitalized_word(msg: &str) -> bool {
     })
 }
 
-fn check_lowercase(filename: &str, contents: &str, bad: &mut bool) {
+fn check_lowercase(filename: &str, contents: &str, check: &mut RunningCheck) {
     let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
 
     for entry in &parse.body {
@@ -45,20 +46,20 @@ fn check_lowercase(filename: &str, contents: &str, bad: &mut bool) {
             && value.chars().next().is_some_and(char::is_uppercase)
             && !is_allowed_capitalized_word(value)
         {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "{filename}: message `{value}` starts with an uppercase letter. Fix it or add it to `ALLOWED_CAPITALIZED_WORDS`"
-            );
+            ));
         }
     }
 }
 
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("fluent_lowercase").path(path));
     walk(
         path,
         |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
         &mut |ent, contents| {
-            check_lowercase(ent.path().to_str().unwrap(), contents, bad);
+            check_lowercase(ent.path().to_str().unwrap(), contents, &mut check);
         },
     );
 }
diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs
index 836b5699289..c7c760b8d54 100644
--- a/src/tools/tidy/src/fluent_period.rs
+++ b/src/tools/tidy/src/fluent_period.rs
@@ -4,6 +4,7 @@ use std::path::Path;
 
 use fluent_syntax::ast::{Entry, PatternElement};
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
 use crate::walk::{filter_dirs, walk};
 
 fn filter_fluent(path: &Path) -> bool {
@@ -20,7 +21,7 @@ const ALLOWLIST: &[&str] = &[
     "incremental_corrupt_file",
 ];
 
-fn check_period(filename: &str, contents: &str, bad: &mut bool) {
+fn check_period(filename: &str, contents: &str, check: &mut RunningCheck) {
     if filename.contains("codegen") {
         // FIXME: Too many codegen messages have periods right now...
         return;
@@ -40,7 +41,7 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) {
                 if value.ends_with(".") && !value.ends_with("...") {
                     let ll = find_line(contents, value);
                     let name = m.id.name;
-                    tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period");
+                    check.error(format!("{filename}:{ll}: message `{name}` ends in a period"));
                 }
             }
 
@@ -56,7 +57,7 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) {
                 {
                     let ll = find_line(contents, value);
                     let name = attr.id.name;
-                    tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period");
+                    check.error(format!("{filename}:{ll}: attr `{name}` ends in a period"));
                 }
             }
         }
@@ -74,12 +75,14 @@ fn find_line(haystack: &str, needle: &str) -> usize {
     1
 }
 
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("fluent_period").path(path));
+
     walk(
         path,
         |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
         &mut |ent, contents| {
-            check_period(ent.path().to_str().unwrap(), contents, bad);
+            check_period(ent.path().to_str().unwrap(), contents, &mut check);
         },
     );
 }
diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs
index 909bf482ddf..2047089631b 100644
--- a/src/tools/tidy/src/fluent_used.rs
+++ b/src/tools/tidy/src/fluent_used.rs
@@ -3,6 +3,7 @@
 use std::collections::HashMap;
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::walk::{filter_dirs, walk};
 
 fn filter_used_messages(
@@ -27,13 +28,15 @@ fn filter_used_messages(
     }
 }
 
-pub fn check(path: &Path, mut all_defined_msgs: HashMap<String, String>, bad: &mut bool) {
+pub fn check(path: &Path, mut all_defined_msgs: HashMap<String, String>, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("fluent_used").path(path));
+
     let mut msgs_appear_only_once = HashMap::new();
     walk(path, |path, _| filter_dirs(path), &mut |_, contents| {
         filter_used_messages(contents, &mut all_defined_msgs, &mut msgs_appear_only_once);
     });
 
     for (name, filename) in msgs_appear_only_once {
-        tidy_error!(bad, "{filename}: message `{}` is not used", name,);
+        check.error(format!("{filename}: message `{name}` is not used"));
     }
 }
diff --git a/src/tools/tidy/src/gcc_submodule.rs b/src/tools/tidy/src/gcc_submodule.rs
index 217eaf1758c..3a6e3247de6 100644
--- a/src/tools/tidy/src/gcc_submodule.rs
+++ b/src/tools/tidy/src/gcc_submodule.rs
@@ -4,7 +4,11 @@
 use std::path::Path;
 use std::process::Command;
 
-pub fn check(root_path: &Path, compiler_path: &Path, bad: &mut bool) {
+use crate::diagnostics::DiagCtx;
+
+pub fn check(root_path: &Path, compiler_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("gcc_submodule");
+
     let cg_gcc_version_path = compiler_path.join("rustc_codegen_gcc/libgccjit.version");
     let cg_gcc_version = std::fs::read_to_string(&cg_gcc_version_path)
         .unwrap_or_else(|_| {
@@ -26,7 +30,7 @@ pub fn check(root_path: &Path, compiler_path: &Path, bad: &mut bool) {
 
     // Git is not available or we are in a tarball
     if !git_output.status.success() {
-        eprintln!("Cannot figure out the SHA of the GCC submodule");
+        check.message("Cannot figure out the SHA of the GCC submodule");
         return;
     }
 
@@ -43,12 +47,11 @@ pub fn check(root_path: &Path, compiler_path: &Path, bad: &mut bool) {
     // The SHA can start with + if the submodule is modified or - if it is not checked out.
     let gcc_submodule_sha = git_output.trim_start_matches(['+', '-']);
     if gcc_submodule_sha != cg_gcc_version {
-        *bad = true;
-        eprintln!(
+        check.error(format!(
             r#"Commit SHA of the src/gcc submodule (`{gcc_submodule_sha}`) does not match the required GCC version of the GCC codegen backend (`{cg_gcc_version}`).
 Make sure to set the src/gcc submodule to commit {cg_gcc_version}.
 The GCC codegen backend commit is configured at {}."#,
             cg_gcc_version_path.display(),
-        );
+        ));
     }
 }
diff --git a/src/tools/tidy/src/known_bug.rs b/src/tools/tidy/src/known_bug.rs
index e1921715ab9..d3b75e0cf5b 100644
--- a/src/tools/tidy/src/known_bug.rs
+++ b/src/tools/tidy/src/known_bug.rs
@@ -2,9 +2,11 @@
 
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::walk::*;
 
-pub fn check(filepath: &Path, bad: &mut bool) {
+pub fn check(filepath: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("known_bug").path(filepath));
     walk(filepath, |path, _is_dir| filter_not_rust(path), &mut |entry, contents| {
         let file: &Path = entry.path();
 
@@ -19,11 +21,10 @@ pub fn check(filepath: &Path, bad: &mut bool) {
             [.., "tests", "crashes", "auxiliary", _aux_file_rs]
         ) && !contents.lines().any(|line| line.starts_with("//@ known-bug: "))
         {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "{} crash/ice test does not have a \"//@ known-bug: \" directive",
                 file.display()
-            );
+            ));
         }
     });
 }
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index f7920e3205a..0bfee93796b 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -11,7 +11,8 @@ use std::{env, io};
 use build_helper::ci::CiEnv;
 use build_helper::git::{GitConfig, get_closest_upstream_commit};
 use build_helper::stage0_parser::{Stage0Config, parse_stage0_file};
-use termcolor::WriteColor;
+
+use crate::diagnostics::{DiagCtx, RunningCheck};
 
 macro_rules! static_regex {
     ($re:literal) => {{
@@ -43,35 +44,6 @@ macro_rules! t {
     };
 }
 
-macro_rules! tidy_error {
-    ($bad:expr, $($fmt:tt)*) => ({
-        $crate::tidy_error(&format_args!($($fmt)*).to_string()).expect("failed to output error");
-        *$bad = true;
-    });
-}
-
-macro_rules! tidy_error_ext {
-    ($tidy_error:path, $bad:expr, $($fmt:tt)*) => ({
-        $tidy_error(&format_args!($($fmt)*).to_string()).expect("failed to output error");
-        *$bad = true;
-    });
-}
-
-fn tidy_error(args: &str) -> std::io::Result<()> {
-    use std::io::Write;
-
-    use termcolor::{Color, ColorChoice, ColorSpec, StandardStream};
-
-    let mut stderr = StandardStream::stdout(ColorChoice::Auto);
-    stderr.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
-
-    write!(&mut stderr, "tidy error")?;
-    stderr.set_color(&ColorSpec::new())?;
-
-    writeln!(&mut stderr, ": {args}")?;
-    Ok(())
-}
-
 pub struct CiInfo {
     pub git_merge_commit_email: String,
     pub nightly_branch: String,
@@ -80,7 +52,9 @@ pub struct CiInfo {
 }
 
 impl CiInfo {
-    pub fn new(bad: &mut bool) -> Self {
+    pub fn new(diag_ctx: DiagCtx) -> Self {
+        let mut check = diag_ctx.start_check("CI history");
+
         let stage0 = parse_stage0_file();
         let Stage0Config { nightly_branch, git_merge_commit_email, .. } = stage0.config;
 
@@ -93,11 +67,14 @@ impl CiInfo {
         let base_commit = match get_closest_upstream_commit(None, &info.git_config(), info.ci_env) {
             Ok(Some(commit)) => Some(commit),
             Ok(None) => {
-                info.error_if_in_ci("no base commit found", bad);
+                info.error_if_in_ci("no base commit found", &mut check);
                 None
             }
             Err(error) => {
-                info.error_if_in_ci(&format!("failed to retrieve base commit: {error}"), bad);
+                info.error_if_in_ci(
+                    &format!("failed to retrieve base commit: {error}"),
+                    &mut check,
+                );
                 None
             }
         };
@@ -112,12 +89,11 @@ impl CiInfo {
         }
     }
 
-    pub fn error_if_in_ci(&self, msg: &str, bad: &mut bool) {
+    pub fn error_if_in_ci(&self, msg: &str, check: &mut RunningCheck) {
         if self.ci_env.is_running_in_ci() {
-            *bad = true;
-            eprintln!("tidy check error: {msg}");
+            check.error(msg);
         } else {
-            eprintln!("tidy check warning: {msg}. Some checks will be skipped.");
+            check.warning(format!("{msg}. Some checks will be skipped."));
         }
     }
 }
@@ -250,6 +226,7 @@ pub mod alphabetical;
 pub mod bins;
 pub mod debug_artifacts;
 pub mod deps;
+pub mod diagnostics;
 pub mod edition;
 pub mod error_codes;
 pub mod extdeps;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index f9e82341b7a..93bc1611199 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -8,10 +8,10 @@ use std::collections::VecDeque;
 use std::num::NonZeroUsize;
 use std::path::PathBuf;
 use std::str::FromStr;
-use std::sync::atomic::{AtomicBool, Ordering};
 use std::thread::{self, ScopedJoinHandle, scope};
 use std::{env, process};
 
+use tidy::diagnostics::{COLOR_ERROR, COLOR_SUCCESS, DiagCtx, output_message};
 use tidy::*;
 
 fn main() {
@@ -50,9 +50,8 @@ fn main() {
     let extra_checks =
         cfg_args.iter().find(|s| s.starts_with("--extra-checks=")).map(String::as_str);
 
-    let mut bad = false;
-    let ci_info = CiInfo::new(&mut bad);
-    let bad = std::sync::Arc::new(AtomicBool::new(bad));
+    let diag_ctx = DiagCtx::new(&root_path, verbose);
+    let ci_info = CiInfo::new(diag_ctx.clone());
 
     let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
         // poll all threads for completion before awaiting the oldest one
@@ -87,12 +86,9 @@ fn main() {
             (@ $p:ident, name=$name:expr $(, $args:expr)* ) => {
                 drain_handles(&mut handles);
 
+                let diag_ctx = diag_ctx.clone();
                 let handle = thread::Builder::new().name($name).spawn_scoped(s, || {
-                    let mut flag = false;
-                    $p::check($($args, )* &mut flag);
-                    if (flag) {
-                        bad.store(true, Ordering::Relaxed);
-                    }
+                    $p::check($($args, )* diag_ctx);
                 }).unwrap();
                 handles.push_back(handle);
             }
@@ -118,7 +114,7 @@ fn main() {
         check!(unknown_revision, &tests_path);
 
         // Checks that only make sense for the compiler.
-        check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose, &ci_info);
+        check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], &ci_info);
         check!(fluent_alphabetical, &compiler_path, bless);
         check!(fluent_period, &compiler_path);
         check!(fluent_lowercase, &compiler_path);
@@ -155,25 +151,12 @@ fn main() {
         check!(x_version, &root_path, &cargo);
 
         check!(triagebot, &root_path);
-
         check!(filenames, &root_path);
 
         let collected = {
             drain_handles(&mut handles);
 
-            let mut flag = false;
-            let r = features::check(
-                &src_path,
-                &tests_path,
-                &compiler_path,
-                &library_path,
-                &mut flag,
-                verbose,
-            );
-            if flag {
-                bad.store(true, Ordering::Relaxed);
-            }
-            r
+            features::check(&src_path, &tests_path, &compiler_path, &library_path, diag_ctx.clone())
         };
         check!(unstable_book, &src_path, collected);
 
@@ -192,8 +175,22 @@ fn main() {
         );
     });
 
-    if bad.load(Ordering::Relaxed) {
-        eprintln!("some tidy checks failed");
+    let failed_checks = diag_ctx.into_failed_checks();
+    if !failed_checks.is_empty() {
+        let mut failed: Vec<String> =
+            failed_checks.into_iter().map(|c| c.id().to_string()).collect();
+        failed.sort();
+        output_message(
+            &format!(
+                "The following check{} failed: {}",
+                if failed.len() > 1 { "s" } else { "" },
+                failed.join(", ")
+            ),
+            None,
+            Some(COLOR_ERROR),
+        );
         process::exit(1);
+    } else {
+        output_message("All tidy checks succeeded", None, Some(COLOR_SUCCESS));
     }
 }
diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs
index 6119eb58383..0f9fab51d09 100644
--- a/src/tools/tidy/src/mir_opt_tests.rs
+++ b/src/tools/tidy/src/mir_opt_tests.rs
@@ -5,9 +5,10 @@ use std::path::{Path, PathBuf};
 
 use miropt_test_tools::PanicStrategy;
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
 use crate::walk::walk_no_read;
 
-fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
+fn check_unused_files(path: &Path, bless: bool, check: &mut RunningCheck) {
     let mut rs_files = Vec::<PathBuf>::new();
     let mut output_files = HashSet::<PathBuf>::new();
 
@@ -37,18 +38,17 @@ fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
 
     for extra in output_files {
         if !bless {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "the following output file is not associated with any mir-opt test, you can remove it: {}",
                 extra.display()
-            );
+            ));
         } else {
             let _ = std::fs::remove_file(extra);
         }
     }
 }
 
-fn check_dash_files(path: &Path, bless: bool, bad: &mut bool) {
+fn check_dash_files(path: &Path, bless: bool, check: &mut RunningCheck) {
     for file in walkdir::WalkDir::new(path.join("mir-opt"))
         .into_iter()
         .filter_map(Result::ok)
@@ -60,11 +60,10 @@ fn check_dash_files(path: &Path, bless: bool, bad: &mut bool) {
             && name.contains('-')
         {
             if !bless {
-                tidy_error!(
-                    bad,
+                check.error(format!(
                     "mir-opt test files should not have dashes in them: {}",
                     path.display()
-                );
+                ));
             } else {
                 let new_name = name.replace('-', "_");
                 let mut new_path = path.to_owned();
@@ -75,7 +74,9 @@ fn check_dash_files(path: &Path, bless: bool, bad: &mut bool) {
     }
 }
 
-pub fn check(path: &Path, bless: bool, bad: &mut bool) {
-    check_unused_files(path, bless, bad);
-    check_dash_files(path, bless, bad);
+pub fn check(path: &Path, bless: bool, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("mir_opt_tests").path(path));
+
+    check_unused_files(path, bless, &mut check);
+    check_dash_files(path, bless, &mut check);
 }
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 991ad55809c..cefad7d9596 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -32,6 +32,7 @@
 
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
 use crate::walk::{filter_dirs, walk};
 
 // Paths that may contain platform-specific code.
@@ -67,7 +68,9 @@ const EXCEPTION_PATHS: &[&str] = &[
     "library/std/src/io/error.rs", // Repr unpacked needed for UEFI
 ];
 
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("pal").path(path));
+
     // Sanity check that the complex parsing here works.
     let mut saw_target_arch = false;
     let mut saw_cfg_bang = false;
@@ -88,7 +91,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             return;
         }
 
-        check_cfgs(contents, file, bad, &mut saw_target_arch, &mut saw_cfg_bang);
+        check_cfgs(contents, file, &mut check, &mut saw_target_arch, &mut saw_cfg_bang);
     });
 
     assert!(saw_target_arch);
@@ -98,7 +101,7 @@ pub fn check(path: &Path, bad: &mut bool) {
 fn check_cfgs(
     contents: &str,
     file: &Path,
-    bad: &mut bool,
+    check: &mut RunningCheck,
     saw_target_arch: &mut bool,
     saw_cfg_bang: &mut bool,
 ) {
@@ -115,7 +118,7 @@ fn check_cfgs(
             Ok(_) => unreachable!(),
             Err(i) => i + 1,
         };
-        tidy_error!(bad, "{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
+        check.error(format!("{}:{line}: platform-specific cfg: {cfg}", file.display()));
     };
 
     for (idx, cfg) in cfgs {
diff --git a/src/tools/tidy/src/rustdoc_css_themes.rs b/src/tools/tidy/src/rustdoc_css_themes.rs
index af36f9ba58e..8d4af7a3bd5 100644
--- a/src/tools/tidy/src/rustdoc_css_themes.rs
+++ b/src/tools/tidy/src/rustdoc_css_themes.rs
@@ -3,7 +3,11 @@
 
 use std::path::Path;
 
-pub fn check(librustdoc_path: &Path, bad: &mut bool) {
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
+
+pub fn check(librustdoc_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("rustdoc_css_themes").path(librustdoc_path));
+
     let rustdoc_css = "html/static/css/rustdoc.css";
     let noscript_css = "html/static/css/noscript.css";
     let rustdoc_css_contents = std::fs::read_to_string(librustdoc_path.join(rustdoc_css))
@@ -14,13 +18,13 @@ pub fn check(librustdoc_path: &Path, bad: &mut bool) {
         "light",
         rustdoc_css_contents.lines().enumerate().map(|(i, l)| (i + 1, l.trim())),
         noscript_css_contents.lines().enumerate().map(|(i, l)| (i + 1, l.trim())),
-        bad,
+        &mut check,
     );
     compare_themes_from_files(
         "dark",
         rustdoc_css_contents.lines().enumerate(),
         noscript_css_contents.lines().enumerate(),
-        bad,
+        &mut check,
     );
 }
 
@@ -28,7 +32,7 @@ fn compare_themes_from_files<'a>(
     name: &str,
     mut rustdoc_css_lines: impl Iterator<Item = (usize, &'a str)>,
     mut noscript_css_lines: impl Iterator<Item = (usize, &'a str)>,
-    bad: &mut bool,
+    check: &mut RunningCheck,
 ) {
     let begin_theme_pat = format!("/* Begin theme: {name}");
     let mut found_theme = None;
@@ -38,10 +42,9 @@ fn compare_themes_from_files<'a>(
             continue;
         }
         if let Some(found_theme) = found_theme {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "rustdoc.css contains two {name} themes on lines {rustdoc_css_line_number} and {found_theme}",
-            );
+            ));
             return;
         }
         found_theme = Some(rustdoc_css_line_number);
@@ -50,14 +53,13 @@ fn compare_themes_from_files<'a>(
                 continue;
             }
             if let Some(found_theme_noscript) = found_theme_noscript {
-                tidy_error!(
-                    bad,
+                check.error(format!(
                     "noscript.css contains two {name} themes on lines {noscript_css_line_number} and {found_theme_noscript}",
-                );
+                ));
                 return;
             }
             found_theme_noscript = Some(noscript_css_line_number);
-            compare_themes(name, &mut rustdoc_css_lines, &mut noscript_css_lines, bad);
+            compare_themes(name, &mut rustdoc_css_lines, &mut noscript_css_lines, check);
         }
     }
 }
@@ -66,7 +68,7 @@ fn compare_themes<'a>(
     name: &str,
     rustdoc_css_lines: impl Iterator<Item = (usize, &'a str)>,
     noscript_css_lines: impl Iterator<Item = (usize, &'a str)>,
-    bad: &mut bool,
+    check: &mut RunningCheck,
 ) {
     let end_theme_pat = format!("/* End theme: {name}");
     for (
@@ -90,12 +92,11 @@ fn compare_themes<'a>(
             break;
         }
         if rustdoc_css_line != noscript_css_line {
-            tidy_error!(
-                bad,
-                "noscript.css:{noscript_css_line_number} and rustdoc.css:{rustdoc_css_line_number} contain copies of {name} theme that are not the same",
-            );
-            eprintln!("- {noscript_css_line}");
-            eprintln!("+ {rustdoc_css_line}");
+            check.error(format!(
+                r#"noscript.css:{noscript_css_line_number} and rustdoc.css:{rustdoc_css_line_number} contain copies of {name} theme that are not the same
+- {noscript_css_line}
++ {rustdoc_css_line}"#,
+            ));
             return;
         }
     }
diff --git a/src/tools/tidy/src/rustdoc_gui_tests.rs b/src/tools/tidy/src/rustdoc_gui_tests.rs
index 3b995f219d2..8ec300c42ce 100644
--- a/src/tools/tidy/src/rustdoc_gui_tests.rs
+++ b/src/tools/tidy/src/rustdoc_gui_tests.rs
@@ -2,18 +2,21 @@
 
 use std::path::Path;
 
-pub fn check(path: &Path, bad: &mut bool) {
+use crate::diagnostics::{CheckId, DiagCtx};
+
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("rustdoc_gui_tests").path(path));
+
     crate::walk::walk(
         &path.join("rustdoc-gui"),
         |p, is_dir| !is_dir && p.extension().is_none_or(|e| e != "goml"),
         &mut |entry, content| {
             for line in content.lines() {
                 if !line.starts_with("// ") {
-                    tidy_error!(
-                        bad,
+                    check.error(format!(
                         "{}: rustdoc-gui tests must start with a small description",
                         entry.path().display(),
-                    );
+                    ));
                     return;
                 } else if line.starts_with("// ") {
                     let parts = line[2..].trim();
diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs
index 722e1ebd0ca..ade774616c7 100644
--- a/src/tools/tidy/src/rustdoc_json.rs
+++ b/src/tools/tidy/src/rustdoc_json.rs
@@ -4,21 +4,26 @@
 use std::path::Path;
 use std::str::FromStr;
 
+use crate::diagnostics::{CheckId, DiagCtx};
+
 const RUSTDOC_JSON_TYPES: &str = "src/rustdoc-json-types";
 
-pub fn check(src_path: &Path, ci_info: &crate::CiInfo, bad: &mut bool) {
-    println!("Checking tidy rustdoc_json...");
+pub fn check(src_path: &Path, ci_info: &crate::CiInfo, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("rustdoc_json").path(src_path));
+
     let Some(base_commit) = &ci_info.base_commit else {
-        eprintln!("No base commit, skipping rustdoc_json check");
+        check.verbose_msg("No base commit, skipping rustdoc_json check");
         return;
     };
 
     // First we check that `src/rustdoc-json-types` was modified.
-    if !crate::files_modified(ci_info, |p| p == RUSTDOC_JSON_TYPES) {
+    if !crate::files_modified(ci_info, |p| p.starts_with(RUSTDOC_JSON_TYPES)) {
         // `rustdoc-json-types` was not modified so nothing more to check here.
-        println!("`rustdoc-json-types` was not modified.");
         return;
     }
+
+    check.message("`rustdoc-json-types` modified, checking format version");
+
     // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated.
     match crate::git_diff(base_commit, src_path.join("rustdoc-json-types")) {
         Some(output) => {
@@ -45,34 +50,29 @@ pub fn check(src_path: &Path, ci_info: &crate::CiInfo, bad: &mut bool) {
                 }
             }
             if format_version_updated != latest_feature_comment_updated {
-                *bad = true;
-                if latest_feature_comment_updated {
-                    eprintln!(
-                        "error in `rustdoc_json` tidy check: `Latest feature` comment was updated \
-                         whereas `FORMAT_VERSION` wasn't in `{RUSTDOC_JSON_TYPES}/lib.rs`"
-                    );
+                let msg = if latest_feature_comment_updated {
+                    format!(
+                        "`Latest feature` comment was updated whereas `FORMAT_VERSION` wasn't in `{RUSTDOC_JSON_TYPES}/lib.rs`"
+                    )
                 } else {
-                    eprintln!(
-                        "error in `rustdoc_json` tidy check: `Latest feature` comment was not \
-                         updated whereas `FORMAT_VERSION` was in `{RUSTDOC_JSON_TYPES}/lib.rs`"
-                    );
-                }
+                    format!(
+                        "`Latest feature` comment was not updated whereas `FORMAT_VERSION` was in `{RUSTDOC_JSON_TYPES}/lib.rs`"
+                    )
+                };
+                check.error(msg);
             }
             match (new_version, old_version) {
                 (Some(new_version), Some(old_version)) if new_version != old_version + 1 => {
-                    *bad = true;
-                    eprintln!(
-                        "error in `rustdoc_json` tidy check: invalid `FORMAT_VERSION` increase in \
-                         `{RUSTDOC_JSON_TYPES}/lib.rs`, should be `{}`, found `{new_version}`",
+                    check.error(format!(
+                        "invalid `FORMAT_VERSION` increase in `{RUSTDOC_JSON_TYPES}/lib.rs`, should be `{}`, found `{new_version}`",
                         old_version + 1,
-                    );
+                    ));
                 }
                 _ => {}
             }
         }
         None => {
-            *bad = true;
-            eprintln!("error: failed to run `git diff` in rustdoc_json check");
+            check.error("failed to run `git diff` in rustdoc_json check");
         }
     }
 }
diff --git a/src/tools/tidy/src/rustdoc_templates.rs b/src/tools/tidy/src/rustdoc_templates.rs
index 597290a6a9a..4e5b9988d53 100644
--- a/src/tools/tidy/src/rustdoc_templates.rs
+++ b/src/tools/tidy/src/rustdoc_templates.rs
@@ -6,12 +6,15 @@ use std::path::Path;
 
 use ignore::DirEntry;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::walk::walk;
 
 // Array containing `("beginning of tag", "end of tag")`.
 const TAGS: &[(&str, &str)] = &[("{#", "#}"), ("{%", "%}"), ("{{", "}}")];
 
-pub fn check(librustdoc_path: &Path, bad: &mut bool) {
+pub fn check(librustdoc_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("rustdoc_templates").path(librustdoc_path));
+
     walk(
         &librustdoc_path.join("html/templates"),
         |path, is_dir| is_dir || path.extension().is_none_or(|ext| ext != OsStr::new("html")),
@@ -46,12 +49,11 @@ pub fn check(librustdoc_path: &Path, bad: &mut bool) {
                         })
                     {
                         // It seems like ending this line with a jinja tag is not needed after all.
-                        tidy_error!(
-                            bad,
+                        check.error(format!(
                             "`{}` at line {}: unneeded `{{# #}}` tag at the end of the line",
                             path.path().display(),
                             pos + 1,
-                        );
+                        ));
                     }
                     continue;
                 }
@@ -67,12 +69,11 @@ pub fn check(librustdoc_path: &Path, bad: &mut bool) {
                 }) {
                     None => {
                         // No it's not, let's error.
-                        tidy_error!(
-                            bad,
+                        check.error(format!(
                             "`{}` at line {}: missing `{{# #}}` at the end of the line",
                             path.path().display(),
                             pos + 1,
-                        );
+                        ));
                     }
                     Some(end_tag) => {
                         // We skip the tag.
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index fca097c091b..d17278edc84 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -24,6 +24,7 @@ use std::sync::LazyLock;
 use regex::RegexSetBuilder;
 use rustc_hash::FxHashMap;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::walk::{filter_dirs, walk};
 
 #[cfg(test)]
@@ -338,7 +339,9 @@ fn is_unexplained_ignore(extension: &str, line: &str) -> bool {
     true
 }
 
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("style").path(path));
+
     fn skip(path: &Path, is_dir: bool) -> bool {
         if path.file_name().is_some_and(|name| name.to_string_lossy().starts_with(".#")) {
             // vim or emacs temporary file
@@ -391,7 +394,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             });
 
         if contents.is_empty() {
-            tidy_error!(bad, "{}: empty file", file.display());
+            check.error(format!("{}: empty file", file.display()));
         }
 
         let extension = file.extension().unwrap().to_string_lossy();
@@ -467,7 +470,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             }
 
             let mut err = |msg: &str| {
-                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
+                check.error(format!("{}:{}: {msg}", file.display(), i + 1));
             };
 
             if trimmed.contains("dbg!")
@@ -611,7 +614,7 @@ pub fn check(path: &Path, bad: &mut bool) {
                     && backtick_count % 2 == 1
                 {
                     let mut err = |msg: &str| {
-                        tidy_error!(bad, "{}:{start_line}: {msg}", file.display());
+                        check.error(format!("{}:{start_line}: {msg}", file.display()));
                     };
                     let block_len = (i + 1) - start_line;
                     if block_len == 1 {
@@ -632,12 +635,12 @@ pub fn check(path: &Path, bad: &mut bool) {
         }
         if leading_new_lines {
             let mut err = |_| {
-                tidy_error!(bad, "{}: leading newline", file.display());
+                check.error(format!("{}: leading newline", file.display()));
             };
             suppressible_tidy_err!(err, skip_leading_newlines, "missing leading newline");
         }
         let mut err = |msg: &str| {
-            tidy_error!(bad, "{}: {}", file.display(), msg);
+            check.error(format!("{}: {}", file.display(), msg));
         };
         match trailing_new_lines {
             0 => suppressible_tidy_err!(err, skip_trailing_newlines, "missing trailing newline"),
@@ -650,38 +653,36 @@ pub fn check(path: &Path, bad: &mut bool) {
         };
         if lines > LINES {
             let mut err = |_| {
-                tidy_error!(
-                    bad,
-                    "{}: too many lines ({}) (add `// \
+                check.error(format!(
+                    "{}: too many lines ({lines}) (add `// \
                      ignore-tidy-filelength` to the file to suppress this error)",
                     file.display(),
-                    lines
-                );
+                ));
             };
             suppressible_tidy_err!(err, skip_file_length, "");
         }
 
         if let Directive::Ignore(false) = skip_cr {
-            tidy_error!(bad, "{}: ignoring CR characters unnecessarily", file.display());
+            check.error(format!("{}: ignoring CR characters unnecessarily", file.display()));
         }
         if let Directive::Ignore(false) = skip_tab {
-            tidy_error!(bad, "{}: ignoring tab characters unnecessarily", file.display());
+            check.error(format!("{}: ignoring tab characters unnecessarily", file.display()));
         }
         if let Directive::Ignore(false) = skip_end_whitespace {
-            tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
+            check.error(format!("{}: ignoring trailing whitespace unnecessarily", file.display()));
         }
         if let Directive::Ignore(false) = skip_trailing_newlines {
-            tidy_error!(bad, "{}: ignoring trailing newlines unnecessarily", file.display());
+            check.error(format!("{}: ignoring trailing newlines unnecessarily", file.display()));
         }
         if let Directive::Ignore(false) = skip_leading_newlines {
-            tidy_error!(bad, "{}: ignoring leading newlines unnecessarily", file.display());
+            check.error(format!("{}: ignoring leading newlines unnecessarily", file.display()));
         }
         if let Directive::Ignore(false) = skip_copyright {
-            tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
+            check.error(format!("{}: ignoring copyright unnecessarily", file.display()));
         }
         // We deliberately do not warn about these being unnecessary,
         // that would just lead to annoying churn.
         let _unused = skip_line_length;
         let _unused = skip_file_length;
-    })
+    });
 }
diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs
index 550932dbfdc..cfcfcaf2435 100644
--- a/src/tools/tidy/src/target_policy.rs
+++ b/src/tools/tidy/src/target_policy.rs
@@ -5,6 +5,7 @@
 use std::collections::HashSet;
 use std::path::Path;
 
+use crate::diagnostics::DiagCtx;
 use crate::walk::{filter_not_rust, walk};
 
 const TARGET_DEFINITIONS_PATH: &str = "compiler/rustc_target/src/spec/targets/";
@@ -23,7 +24,9 @@ const EXCEPTIONS: &[&str] = &[
     "xtensa_esp32s3_espidf",
 ];
 
-pub fn check(root_path: &Path, bad: &mut bool) {
+pub fn check(root_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("target_policy");
+
     let mut targets_to_find = HashSet::new();
 
     let definitions_path = root_path.join(TARGET_DEFINITIONS_PATH);
@@ -55,7 +58,7 @@ pub fn check(root_path: &Path, bad: &mut bool) {
 
     for target in targets_to_find {
         if !EXCEPTIONS.contains(&target.as_str()) {
-            tidy_error!(bad, "{ASSEMBLY_LLVM_TEST_PATH}: missing assembly test for {target}")
+            check.error(format!("{ASSEMBLY_LLVM_TEST_PATH}: missing assembly test for {target}"));
         }
     }
 }
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index b2d5f259eb2..c1db3874ad5 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -4,6 +4,7 @@
 use std::collections::BTreeMap;
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::iter_header::{HeaderLine, iter_header};
 use crate::walk::filter_not_rust;
 
@@ -16,7 +17,9 @@ struct RevisionInfo<'a> {
     llvm_components: Option<Vec<&'a str>>,
 }
 
-pub fn check(tests_path: &Path, bad: &mut bool) {
+pub fn check(tests_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("target-specific-tests").path(tests_path));
+
     crate::walk::walk(tests_path, |path, _is_dir| filter_not_rust(path), &mut |entry, content| {
         if content.contains("// ignore-tidy-target-specific-tests") {
             return;
@@ -44,8 +47,7 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                 } else if let Some((arch, _)) = v.split_once("-") {
                     info.target_arch.replace(Some(arch));
                 } else {
-                    eprintln!("{file}: seems to have a malformed --target value");
-                    *bad = true;
+                    check.error(format!("{file}: seems to have a malformed --target value"));
                 }
             }
         });
@@ -62,25 +64,22 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                 (Some(target_arch), None) => {
                     let llvm_component =
                         target_arch.map_or_else(|| "<arch>".to_string(), arch_to_llvm_component);
-                    eprintln!(
+                    check.error(format!(
                         "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
-                    );
-                    *bad = true;
+                    ));
                 }
                 (None, Some(_)) => {
-                    eprintln!(
+                    check.error(format!(
                         "{file}: revision {rev} should not specify `{LLVM_COMPONENTS_HEADER}` as it doesn't need `--target`"
-                    );
-                    *bad = true;
+                    ));
                 }
                 (Some(target_arch), Some(llvm_components)) => {
                     if let Some(target_arch) = target_arch {
                         let llvm_component = arch_to_llvm_component(target_arch);
                         if !llvm_components.contains(&llvm_component.as_str()) {
-                            eprintln!(
+                            check.error(format!(
                                 "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
-                            );
-                            *bad = true;
+                            ));
                         }
                     }
                 }
diff --git a/src/tools/tidy/src/tests_placement.rs b/src/tools/tidy/src/tests_placement.rs
index 9d0057df8bc..8ba8cf552bd 100644
--- a/src/tools/tidy/src/tests_placement.rs
+++ b/src/tools/tidy/src/tests_placement.rs
@@ -1,15 +1,18 @@
 use std::path::Path;
 
+use crate::diagnostics::DiagCtx;
+
 const FORBIDDEN_PATH: &str = "src/test";
 const ALLOWED_PATH: &str = "tests";
 
-pub fn check(root_path: impl AsRef<Path>, bad: &mut bool) {
-    if root_path.as_ref().join(FORBIDDEN_PATH).exists() {
-        tidy_error!(
-            bad,
+pub fn check(root_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("tests_placement");
+
+    if root_path.join(FORBIDDEN_PATH).exists() {
+        check.error(format!(
             "Tests have been moved, please move them from {} to {}",
-            root_path.as_ref().join(FORBIDDEN_PATH).display(),
-            root_path.as_ref().join(ALLOWED_PATH).display()
-        )
+            root_path.join(FORBIDDEN_PATH).display(),
+            root_path.join(ALLOWED_PATH).display()
+        ));
     }
 }
diff --git a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
index 02412b6f190..1738088a3a0 100644
--- a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
+++ b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
@@ -4,6 +4,7 @@ use std::collections::{BTreeMap, BTreeSet};
 use std::ffi::OsStr;
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::iter_header::*;
 use crate::walk::*;
 
@@ -21,7 +22,10 @@ const IGNORES: &[&str] = &[
 const EXTENSIONS: &[&str] = &["stdout", "stderr"];
 const SPECIAL_TEST: &str = "tests/ui/command/need-crate-arg-ignore-tidy.x.rs";
 
-pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
+pub fn check(tests_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx
+        .start_check(CheckId::new("tests_revision_unpaired_stdout_stderr").path(tests_path));
+
     // Recurse over subdirectories under `tests/`
     walk_dir(tests_path.as_ref(), filter, &mut |entry| {
         // We are inspecting a folder. Collect the paths to interesting files `.rs`, `.stderr`,
@@ -122,12 +126,11 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
                 [] | [_] => return,
                 [_, _] if !expected_revisions.is_empty() => {
                     // Found unrevisioned output files for a revisioned test.
-                    tidy_error!(
-                        bad,
+                    check.error(format!(
                         "found unrevisioned output file `{}` for a revisioned test `{}`",
                         sibling.display(),
                         test_path.display(),
-                    );
+                    ));
                 }
                 [_, _] => return,
                 [_, found_revision, .., extension] => {
@@ -138,13 +141,12 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
                     {
                         // Found some unexpected revision-esque component that is not a known
                         // compare-mode or expected revision.
-                        tidy_error!(
-                            bad,
+                        check.error(format!(
                             "found output file `{}` for unexpected revision `{}` of test `{}`",
                             sibling.display(),
                             found_revision,
                             test_path.display()
-                        );
+                        ));
                     }
                 }
             }
diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs
index 6f25ed616fa..41d61dcd141 100644
--- a/src/tools/tidy/src/triagebot.rs
+++ b/src/tools/tidy/src/triagebot.rs
@@ -4,7 +4,10 @@ use std::path::Path;
 
 use toml::Value;
 
-pub fn check(path: &Path, bad: &mut bool) {
+use crate::diagnostics::DiagCtx;
+
+pub fn check(path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("triagebot");
     let triagebot_path = path.join("triagebot.toml");
 
     // This check is mostly to catch broken path filters *within* `triagebot.toml`, and not enforce
@@ -30,17 +33,14 @@ pub fn check(path: &Path, bad: &mut bool) {
             let full_path = path.join(clean_path);
 
             if !full_path.exists() {
-                tidy_error!(
-                    bad,
-                    "triagebot.toml [mentions.*] contains path '{}' which doesn't exist",
-                    clean_path
-                );
+                check.error(format!(
+                    "triagebot.toml [mentions.*] contains path '{clean_path}' which doesn't exist"
+                ));
             }
         }
     } else {
-        tidy_error!(
-            bad,
-            "triagebot.toml missing [mentions.*] section, this wrong for rust-lang/rust repo."
+        check.error(
+            "triagebot.toml missing [mentions.*] section, this wrong for rust-lang/rust repo.",
         );
     }
 
@@ -55,16 +55,13 @@ pub fn check(path: &Path, bad: &mut bool) {
                 let full_path = path.join(clean_path);
 
                 if !full_path.exists() {
-                    tidy_error!(
-                        bad,
-                        "triagebot.toml [assign.owners] contains path '{}' which doesn't exist",
-                        clean_path
-                    );
+                    check.error(format!(
+                        "triagebot.toml [assign.owners] contains path '{clean_path}' which doesn't exist"
+                    ));
                 }
             }
         } else {
-            tidy_error!(
-                bad,
+            check.error(
                 "triagebot.toml missing [assign.owners] section, this wrong for rust-lang/rust repo."
             );
         }
@@ -86,12 +83,9 @@ pub fn check(path: &Path, bad: &mut bool) {
 
                         // Handle both file and directory paths
                         if !full_path.exists() {
-                            tidy_error!(
-                                bad,
-                                "triagebot.toml [autolabel.{}] contains trigger_files path '{}' which doesn't exist",
-                                label,
-                                file_str
-                            );
+                            check.error(format!(
+                                "triagebot.toml [autolabel.{label}] contains trigger_files path '{file_str}' which doesn't exist",
+                            ));
                         }
                     }
                 }
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 5bf966b658c..12eca47c171 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,13 +7,16 @@ use std::fs;
 use std::io::Write;
 use std::path::{Path, PathBuf};
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
+
 const ISSUES_TXT_HEADER: &str = r#"============================================================
     ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️
 ============================================================
 "#;
 
-pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
+pub fn check(root_path: &Path, bless: bool, diag_ctx: DiagCtx) {
     let path = &root_path.join("tests");
+    let mut check = diag_ctx.start_check(CheckId::new("ui_tests").path(path));
 
     // the list of files in ui tests that are allowed to start with `issue-XXXX`
     // BTreeSet because we would like a stable ordering so --bless works
@@ -33,16 +36,15 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
         .collect();
 
     if !is_sorted && !bless {
-        tidy_error!(
-            bad,
+        check.error(
             "`src/tools/tidy/src/issues.txt` is not in order, mostly because you modified it manually,
             please only update it with command `x test tidy --bless`"
         );
     }
 
-    deny_new_top_level_ui_tests(bad, &path.join("ui"));
+    deny_new_top_level_ui_tests(&mut check, &path.join("ui"));
 
-    let remaining_issue_names = recursively_check_ui_tests(bad, path, &allowed_issue_names);
+    let remaining_issue_names = recursively_check_ui_tests(&mut check, path, &allowed_issue_names);
 
     // if there are any file names remaining, they were moved on the fs.
     // our data must remain up to date, so it must be removed from issues.txt
@@ -64,16 +66,15 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
         for file_name in remaining_issue_names {
             let mut p = PathBuf::from(path);
             p.push(file_name);
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "file `{}` no longer exists and should be removed from the exclusions in `src/tools/tidy/src/issues.txt`",
                 p.display()
-            );
+            ));
         }
     }
 }
 
-fn deny_new_top_level_ui_tests(bad: &mut bool, tests_path: &Path) {
+fn deny_new_top_level_ui_tests(check: &mut RunningCheck, tests_path: &Path) {
     // See <https://github.com/rust-lang/compiler-team/issues/902> where we propose banning adding
     // new ui tests *directly* under `tests/ui/`. For more context, see:
     //
@@ -93,16 +94,15 @@ fn deny_new_top_level_ui_tests(bad: &mut bool, tests_path: &Path) {
         })
         .filter(|e| !e.file_type().is_dir());
     for entry in top_level_ui_tests {
-        tidy_error!(
-            bad,
+        check.error(format!(
             "ui tests should be added under meaningful subdirectories: `{}`",
             entry.path().display()
-        )
+        ));
     }
 }
 
 fn recursively_check_ui_tests<'issues>(
-    bad: &mut bool,
+    check: &mut RunningCheck,
     path: &Path,
     allowed_issue_names: &'issues BTreeSet<&'issues str>,
 ) -> BTreeSet<&'issues str> {
@@ -113,19 +113,19 @@ fn recursively_check_ui_tests<'issues>(
     crate::walk::walk_no_read(&paths, |_, _| false, &mut |entry| {
         let file_path = entry.path();
         if let Some(ext) = file_path.extension().and_then(OsStr::to_str) {
-            check_unexpected_extension(bad, file_path, ext);
+            check_unexpected_extension(check, file_path, ext);
 
             // NB: We do not use file_stem() as some file names have multiple `.`s and we
             // must strip all of them.
             let testname =
                 file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
             if ext == "stderr" || ext == "stdout" || ext == "fixed" {
-                check_stray_output_snapshot(bad, file_path, testname);
-                check_empty_output_snapshot(bad, file_path);
+                check_stray_output_snapshot(check, file_path, testname);
+                check_empty_output_snapshot(check, file_path);
             }
 
             deny_new_nondescriptive_test_names(
-                bad,
+                check,
                 path,
                 &mut remaining_issue_names,
                 file_path,
@@ -137,7 +137,7 @@ fn recursively_check_ui_tests<'issues>(
     remaining_issue_names
 }
 
-fn check_unexpected_extension(bad: &mut bool, file_path: &Path, ext: &str) {
+fn check_unexpected_extension(check: &mut RunningCheck, file_path: &Path, ext: &str) {
     const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
         "rs",     // test source files
         "stderr", // expected stderr file, corresponds to a rs file
@@ -178,11 +178,11 @@ fn check_unexpected_extension(bad: &mut bool, file_path: &Path, ext: &str) {
     if !(EXPECTED_TEST_FILE_EXTENSIONS.contains(&ext)
         || EXTENSION_EXCEPTION_PATHS.iter().any(|path| file_path.ends_with(path)))
     {
-        tidy_error!(bad, "file {} has unexpected extension {}", file_path.display(), ext);
+        check.error(format!("file {} has unexpected extension {}", file_path.display(), ext));
     }
 }
 
-fn check_stray_output_snapshot(bad: &mut bool, file_path: &Path, testname: &str) {
+fn check_stray_output_snapshot(check: &mut RunningCheck, file_path: &Path, testname: &str) {
     // Test output filenames have one of the formats:
     // ```
     // $testname.stderr
@@ -197,20 +197,20 @@ fn check_stray_output_snapshot(bad: &mut bool, file_path: &Path, testname: &str)
     if !file_path.with_file_name(testname).with_extension("rs").exists()
         && !testname.contains("ignore-tidy")
     {
-        tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
+        check.error(format!("Stray file with UI testing output: {:?}", file_path));
     }
 }
 
-fn check_empty_output_snapshot(bad: &mut bool, file_path: &Path) {
+fn check_empty_output_snapshot(check: &mut RunningCheck, file_path: &Path) {
     if let Ok(metadata) = fs::metadata(file_path)
         && metadata.len() == 0
     {
-        tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
+        check.error(format!("Empty file with UI testing output: {:?}", file_path));
     }
 }
 
 fn deny_new_nondescriptive_test_names(
-    bad: &mut bool,
+    check: &mut RunningCheck,
     path: &Path,
     remaining_issue_names: &mut BTreeSet<&str>,
     file_path: &Path,
@@ -231,11 +231,10 @@ fn deny_new_nondescriptive_test_names(
         if !remaining_issue_names.remove(stripped_path.as_str())
             && !stripped_path.starts_with("ui/issues/")
         {
-            tidy_error!(
-                bad,
+            check.error(format!(
                 "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`",
                 issue_n = &test_name[1],
-            );
+            ));
         }
     }
 }
diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs
index 7396310ed37..cab445ac63a 100644
--- a/src/tools/tidy/src/unit_tests.rs
+++ b/src/tools/tidy/src/unit_tests.rs
@@ -11,9 +11,12 @@
 
 use std::path::Path;
 
+use crate::diagnostics::{CheckId, DiagCtx};
 use crate::walk::{filter_dirs, walk};
 
-pub fn check(root_path: &Path, stdlib: bool, bad: &mut bool) {
+pub fn check(root_path: &Path, stdlib: bool, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("unit_tests").path(root_path));
+
     let skip = move |path: &Path, is_dir| {
         let file_name = path.file_name().unwrap_or_default();
 
@@ -92,14 +95,11 @@ pub fn check(root_path: &Path, stdlib: bool, bad: &mut bool) {
                         .to_owned()
                 };
                 let name = if is_test() { "test" } else { "bench" };
-                tidy_error!(
-                    bad,
-                    "`{}:{}` contains `#[{}]`; {}",
+                check.error(format!(
+                    "`{}:{}` contains `#[{name}]`; {explanation}",
                     path.display(),
                     i + 1,
-                    name,
-                    explanation,
-                );
+                ));
                 return;
             }
         }
diff --git a/src/tools/tidy/src/unknown_revision.rs b/src/tools/tidy/src/unknown_revision.rs
index 0ba05c80a79..776d45e25de 100644
--- a/src/tools/tidy/src/unknown_revision.rs
+++ b/src/tools/tidy/src/unknown_revision.rs
@@ -12,12 +12,14 @@ use std::sync::OnceLock;
 use ignore::DirEntry;
 use regex::Regex;
 
+use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
 use crate::iter_header::{HeaderLine, iter_header};
 use crate::walk::{filter_dirs, filter_not_rust, walk};
 
-pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
+pub fn check(tests_path: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("unknown_revision").path(tests_path));
     walk(
-        tests_path.as_ref(),
+        tests_path,
         |path, is_dir| {
             filter_dirs(path) || filter_not_rust(path) || {
                 // Auxiliary source files for incremental tests can refer to revisions
@@ -25,11 +27,11 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
                 is_dir && path.file_name().is_some_and(|name| name == "auxiliary")
             }
         },
-        &mut |entry, contents| visit_test_file(entry, contents, bad),
+        &mut |entry, contents| visit_test_file(entry, contents, &mut check),
     );
 }
 
-fn visit_test_file(entry: &DirEntry, contents: &str, bad: &mut bool) {
+fn visit_test_file(entry: &DirEntry, contents: &str, check: &mut RunningCheck) {
     let mut revisions = HashSet::new();
     let mut unused_revision_names = HashSet::new();
 
@@ -68,10 +70,9 @@ fn visit_test_file(entry: &DirEntry, contents: &str, bad: &mut bool) {
 
     // Fail if any revision names appear in both places, since that's probably a mistake.
     for rev in revisions.intersection(&unused_revision_names).copied().collect::<BTreeSet<_>>() {
-        tidy_error!(
-            bad,
+        check.error(format!(
             "revision name [{rev}] appears in both `revisions` and `unused-revision-names` in {path}"
-        );
+        ));
     }
 
     // Compute the set of revisions that were mentioned but not declared,
@@ -84,7 +85,7 @@ fn visit_test_file(entry: &DirEntry, contents: &str, bad: &mut bool) {
     bad_revisions.sort();
 
     for (line_number, rev) in bad_revisions {
-        tidy_error!(bad, "unknown revision [{rev}] at {path}:{line_number}");
+        check.error(format!("unknown revision [{rev}] at {path}:{line_number}"));
     }
 }
 
diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs
index 0ed954d48de..bab294abee0 100644
--- a/src/tools/tidy/src/unstable_book.rs
+++ b/src/tools/tidy/src/unstable_book.rs
@@ -2,6 +2,7 @@ use std::collections::BTreeSet;
 use std::fs;
 use std::path::{Path, PathBuf};
 
+use crate::diagnostics::{DiagCtx, RunningCheck};
 use crate::features::{CollectedFeatures, Features, Status};
 
 pub const PATH_STR: &str = "doc/unstable-book";
@@ -75,19 +76,18 @@ fn collect_unstable_book_lib_features_section_file_names(base_src_path: &Path) -
 }
 
 /// Would switching underscores for dashes work?
-fn maybe_suggest_dashes(names: &BTreeSet<String>, feature_name: &str, bad: &mut bool) {
+fn maybe_suggest_dashes(names: &BTreeSet<String>, feature_name: &str, check: &mut RunningCheck) {
     let with_dashes = feature_name.replace('_', "-");
     if names.contains(&with_dashes) {
-        tidy_error!(
-            bad,
-            "the file `{}.md` contains underscores; use dashes instead: `{}.md`",
-            feature_name,
-            with_dashes,
-        );
+        check.error(format!(
+            "the file `{feature_name}.md` contains underscores; use dashes instead: `{with_dashes}.md`",
+        ));
     }
 }
 
-pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) {
+pub fn check(path: &Path, features: CollectedFeatures, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check("unstable_book");
+
     let lang_features = features.lang;
     let lib_features = features
         .lib
@@ -108,26 +108,22 @@ pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) {
     // Check for Unstable Book sections that don't have a corresponding unstable feature
     for feature_name in &unstable_book_lib_features_section_file_names - &unstable_lib_feature_names
     {
-        tidy_error!(
-            bad,
-            "The Unstable Book has a 'library feature' section '{}' which doesn't \
-                         correspond to an unstable library feature",
-            feature_name
-        );
-        maybe_suggest_dashes(&unstable_lib_feature_names, &feature_name, bad);
+        check.error(format!(
+            "The Unstable Book has a 'library feature' section '{feature_name}' which doesn't \
+                         correspond to an unstable library feature"
+        ));
+        maybe_suggest_dashes(&unstable_lib_feature_names, &feature_name, &mut check);
     }
 
     // Check for Unstable Book sections that don't have a corresponding unstable feature.
     for feature_name in
         &unstable_book_lang_features_section_file_names - &unstable_lang_feature_names
     {
-        tidy_error!(
-            bad,
-            "The Unstable Book has a 'language feature' section '{}' which doesn't \
-                     correspond to an unstable language feature",
-            feature_name
-        );
-        maybe_suggest_dashes(&unstable_lang_feature_names, &feature_name, bad);
+        check.error(format!(
+            "The Unstable Book has a 'language feature' section '{feature_name}' which doesn't \
+                     correspond to an unstable language feature"
+        ));
+        maybe_suggest_dashes(&unstable_lang_feature_names, &feature_name, &mut check);
     }
 
     // List unstable features that don't have Unstable Book sections.
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 9f7f43c4000..b3e322d9403 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -3,12 +3,18 @@ use std::process::{Command, Stdio};
 
 use semver::Version;
 
-pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+use crate::diagnostics::{CheckId, DiagCtx};
+
+pub fn check(root: &Path, cargo: &Path, diag_ctx: DiagCtx) {
+    let mut check = diag_ctx.start_check(CheckId::new("x_version").path(root));
     let cargo_list = Command::new(cargo).args(["install", "--list"]).stdout(Stdio::piped()).spawn();
 
     let child = match cargo_list {
         Ok(child) => child,
-        Err(e) => return tidy_error!(bad, "failed to run `cargo`: {}", e),
+        Err(e) => {
+            check.error(format!("failed to run `cargo`: {e}"));
+            return;
+        }
     };
 
     let cargo_list = child.wait_with_output().unwrap();
@@ -47,13 +53,10 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
                 )
             }
         } else {
-            tidy_error!(
-                bad,
-                "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
-            )
+            check.error("Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`")
         }
     } else {
-        tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status)
+        check.error(format!("failed to check version of `x`: {}", cargo_list.status))
     }
 }
 
diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs
index a7c6173d88c..16550f83003 100644
--- a/src/tools/unstable-book-gen/src/main.rs
+++ b/src/tools/unstable-book-gen/src/main.rs
@@ -5,6 +5,7 @@ use std::env;
 use std::fs::{self, write};
 use std::path::Path;
 
+use tidy::diagnostics::RunningCheck;
 use tidy::features::{Features, collect_env_vars, collect_lang_features, collect_lib_features};
 use tidy::t;
 use tidy::unstable_book::{
@@ -122,7 +123,7 @@ fn main() {
     let src_path = Path::new(&src_path_str);
     let dest_path = Path::new(&dest_path_str);
 
-    let lang_features = collect_lang_features(compiler_path, &mut false);
+    let lang_features = collect_lang_features(compiler_path, &mut RunningCheck::new_noop());
     let lib_features = collect_lib_features(library_path)
         .into_iter()
         .filter(|&(ref name, _)| !lang_features.contains_key(name))
diff --git a/tests/assembly-llvm/aarch64-pointer-auth.rs b/tests/assembly-llvm/aarch64-pointer-auth.rs
index 56a26df469f..e1ca6d77581 100644
--- a/tests/assembly-llvm/aarch64-pointer-auth.rs
+++ b/tests/assembly-llvm/aarch64-pointer-auth.rs
@@ -1,10 +1,13 @@
 // Test that PAC instructions are emitted when branch-protection is specified.
 
 //@ add-core-stubs
-//@ revisions: PACRET PAUTHLR_NOP PAUTHLR
+//@ revisions: GCS PACRET PAUTHLR_NOP PAUTHLR
 //@ assembly-output: emit-asm
 //@ needs-llvm-components: aarch64
 //@ compile-flags: --target aarch64-unknown-linux-gnu
+//@ [GCS] min-llvm-version: 21
+//@ [GCS] ignore-apple (XCode version needs updating)
+//@ [GCS] compile-flags: -Z branch-protection=gcs
 //@ [PACRET] compile-flags: -Z branch-protection=pac-ret,leaf
 //@ [PAUTHLR_NOP] compile-flags: -Z branch-protection=pac-ret,pc,leaf
 //@ [PAUTHLR] compile-flags: -C target-feature=+pauth-lr -Z branch-protection=pac-ret,pc,leaf
@@ -17,6 +20,7 @@
 extern crate minicore;
 use minicore::*;
 
+// GCS: .aeabi_attribute 2, 1 // Tag_Feature_GCS
 // PACRET: hint #25
 // PACRET: hint #29
 // PAUTHLR_NOP: hint #25
diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs
index b5c116cdfef..ebea9fe40f5 100644
--- a/tests/assembly-llvm/targets/targets-elf.rs
+++ b/tests/assembly-llvm/targets/targets-elf.rs
@@ -658,6 +658,9 @@
 //@ revisions: x86_64_unknown_managarm_mlibc
 //@ [x86_64_unknown_managarm_mlibc] compile-flags: --target x86_64-unknown-managarm-mlibc
 //@ [x86_64_unknown_managarm_mlibc] needs-llvm-components: x86
+//@ revisions: x86_64_unknown_motor
+//@ [x86_64_unknown_motor] compile-flags: --target x86_64-unknown-motor
+//@ [x86_64_unknown_motor] needs-llvm-components: x86
 //@ revisions: x86_64_unknown_netbsd
 //@ [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd
 //@ [x86_64_unknown_netbsd] needs-llvm-components: x86
diff --git a/tests/codegen-llvm/asm/powerpc-clobbers.rs b/tests/codegen-llvm/asm/powerpc-clobbers.rs
index f7fc7eea5d5..10d7ae4dba4 100644
--- a/tests/codegen-llvm/asm/powerpc-clobbers.rs
+++ b/tests/codegen-llvm/asm/powerpc-clobbers.rs
@@ -58,10 +58,10 @@ pub unsafe fn v0_clobber() {
 
 // Output format depends on the availability of altivec.
 // CHECK-LABEL: @clobber_abi
-// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
-// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
-// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
-// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
+// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
+// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
+// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
+// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
 #[no_mangle]
 pub unsafe fn clobber_abi() {
     asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
diff --git a/tests/codegen-llvm/asm/readonly-not-pure.rs b/tests/codegen-llvm/asm/readonly-not-pure.rs
new file mode 100644
index 00000000000..a3c0e276c7f
--- /dev/null
+++ b/tests/codegen-llvm/asm/readonly-not-pure.rs
@@ -0,0 +1,48 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target x86_64-unknown-linux-gnu
+//@ needs-llvm-components: x86
+
+#![crate_type = "rlib"]
+#![feature(no_core)]
+#![no_core]
+
+// Test that when an inline assembly block specifies `readonly` but not `pure`, a detailed
+// `MemoryEffects` is provided to LLVM: this assembly block is not allowed to perform writes,
+// but it may have side-effects.
+
+extern crate minicore;
+use minicore::*;
+
+pub static mut VAR: i32 = 0;
+
+// CHECK-LABEL: @no_options
+// CHECK: call i32 asm
+#[no_mangle]
+pub unsafe fn no_options() -> i32 {
+    VAR = 1;
+    let _ignored: i32;
+    asm!("mov {0}, 1", out(reg) _ignored);
+    VAR
+}
+
+// CHECK-LABEL: @readonly_pure
+// CHECK-NOT: call i32 asm
+#[no_mangle]
+pub unsafe fn readonly_pure() -> i32 {
+    VAR = 1;
+    let _ignored: i32;
+    asm!("mov {0}, 1", out(reg) _ignored, options(pure, readonly));
+    VAR
+}
+
+// CHECK-LABEL: @readonly_not_pure
+// CHECK: call i32 asm {{.*}} #[[ATTR:[0-9]+]]
+#[no_mangle]
+pub unsafe fn readonly_not_pure() -> i32 {
+    VAR = 1;
+    let _ignored: i32;
+    asm!("mov {0}, 1", out(reg) _ignored, options(readonly));
+    VAR
+}
+
+// CHECK: attributes #[[ATTR]] = { nounwind memory(read, inaccessiblemem: readwrite) }
diff --git a/tests/codegen-llvm/branch-protection.rs b/tests/codegen-llvm/branch-protection.rs
index d67e494cc0d..f92259c941c 100644
--- a/tests/codegen-llvm/branch-protection.rs
+++ b/tests/codegen-llvm/branch-protection.rs
@@ -1,9 +1,10 @@
 // Test that the correct module flags are emitted with different branch protection flags.
 
 //@ add-core-stubs
-//@ revisions: BTI PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE
+//@ revisions: BTI GCS PACRET LEAF BKEY PAUTHLR PAUTHLR_BKEY PAUTHLR_LEAF PAUTHLR_BTI NONE
 //@ needs-llvm-components: aarch64
 //@ [BTI] compile-flags: -Z branch-protection=bti
+//@ [GCS] compile-flags: -Z branch-protection=gcs
 //@ [PACRET] compile-flags: -Z branch-protection=pac-ret
 //@ [LEAF] compile-flags: -Z branch-protection=pac-ret,leaf
 //@ [BKEY] compile-flags: -Z branch-protection=pac-ret,b-key
@@ -32,6 +33,9 @@ pub fn test() {}
 // BTI: !"sign-return-address-all", i32 0
 // BTI: !"sign-return-address-with-bkey", i32 0
 
+// GCS: attributes [[ATTR]] = {{.*}} "guarded-control-stack"
+// GCS: !"guarded-control-stack", i32 1
+
 // PACRET: attributes [[ATTR]] = {{.*}} "sign-return-address"="non-leaf"
 // PACRET-SAME: "sign-return-address-key"="a_key"
 // PACRET: !"branch-target-enforcement", i32 0
diff --git a/tests/codegen-llvm/global-allocator-attributes.rs b/tests/codegen-llvm/global-allocator-attributes.rs
new file mode 100644
index 00000000000..472ca772075
--- /dev/null
+++ b/tests/codegen-llvm/global-allocator-attributes.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: -C opt-level=3
+#![crate_type = "lib"]
+
+mod foobar {
+    use std::alloc::{GlobalAlloc, Layout};
+
+    struct Allocator;
+
+    unsafe impl GlobalAlloc for Allocator {
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            // CHECK-LABEL: ; __rustc::__rust_alloc
+            // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,uninitialized,aligned") allocsize(0){{.*}}
+            // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc(i[[SIZE:[0-9]+]] {{.*}}%size, i[[SIZE]] allocalign{{.*}} %align)
+            panic!()
+        }
+
+        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+            // CHECK-LABEL: ; __rustc::__rust_dealloc
+            // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("free"){{.*}}
+            // CHECK-NEXT: define{{.*}} void @{{.*}}__rust_dealloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] {{.*}} %align)
+            panic!()
+        }
+
+        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+            // CHECK-LABEL: ; __rustc::__rust_realloc
+            // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("realloc,aligned") allocsize(3){{.*}}
+            // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_realloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align, i[[SIZE]] {{.*}} %new_size)
+            panic!()
+        }
+
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            // CHECK-LABEL: ; __rustc::__rust_alloc_zeroed
+            // CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,zeroed,aligned") allocsize(0){{.*}}
+            // CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc_zeroed(i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align)
+            panic!()
+        }
+    }
+
+    #[global_allocator]
+    static GLOBAL: Allocator = Allocator;
+}
diff --git a/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs
index 4bec579831d..255f20e6ff6 100644
--- a/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs
+++ b/tests/codegen-llvm/intrinsic-no-unnamed-attr.rs
@@ -7,7 +7,5 @@ use std::intrinsics::sqrtf32;
 // CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}}
 
 fn main() {
-    unsafe {
-        sqrtf32(0.0f32);
-    }
+    sqrtf32(0.0f32);
 }
diff --git a/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs b/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs
new file mode 100644
index 00000000000..b97729fa146
--- /dev/null
+++ b/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+//@ needs-deterministic-layouts
+
+// Currently Vec<T> and &[T] have layouts that start with (pointer, len)
+// which makes the conversion branchless.
+// A nice-to-have property, not guaranteed.
+#![crate_type = "cdylib"]
+
+// CHECK-LABEL: @branchless_cow_slices
+#[no_mangle]
+pub fn branchless_cow_slices<'a>(cow: &'a std::borrow::Cow<'a, [u8]>) -> &'a [u8] {
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    // CHECK-NOT: icmp
+    // CHECK: ret { ptr, {{i32|i64}} }
+    &*cow
+}
diff --git a/tests/codegen-llvm/pattern_type_symbols.rs b/tests/codegen-llvm/pattern_type_symbols.rs
index e86a9ef27de..a90262ff12d 100644
--- a/tests/codegen-llvm/pattern_type_symbols.rs
+++ b/tests/codegen-llvm/pattern_type_symbols.rs
@@ -16,7 +16,7 @@ pub fn bar() {
     // CHECK: call pattern_type_symbols::foo::<u32>
     // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_
     foo::<u32>();
-    // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999])>
-    // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_EEB2_
+    // CHECK: call pattern_type_symbols::foo::<u32 is 0..=999999999>
+    // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooWmRm0_m3b9ac9ff_EB2_
     foo::<NanoU32>();
 }
diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map
index d1d751ff24b..e42b5591c0f 100644
--- a/tests/coverage/issue-83601.cov-map
+++ b/tests/coverage/issue-83601.cov-map
@@ -1,30 +1,22 @@
 Function name: issue_83601::main
-Raw bytes (76): 0x[01, 01, 01, 05, 09, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 01, 00, 02]
+Raw bytes (74): 0x[01, 01, 00, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => $DIR/issue-83601.rs
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+Number of expressions: 0
 Number of file 0 mappings: 14
 - Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12)
 - Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21)
 - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12)
-- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21)
-- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13)
-    = (c1 - c2)
-- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20)
-    = (c1 - c2)
-- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13)
-    = (c1 - c2)
-- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20)
-    = (c1 - c2)
-- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13)
-    = (c1 - c2)
-- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20)
-    = (c1 - c2)
-- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 - c2)
-Highest counter ID seen: c1
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12)
+- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c0
 
diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map
index 2b643ea599e..e5bb1afdcc2 100644
--- a/tests/coverage/issue-84561.cov-map
+++ b/tests/coverage/issue-84561.cov-map
@@ -73,20 +73,20 @@ Number of file 0 mappings: 4
 Highest counter ID seen: c0
 
 Function name: issue_84561::test3
-Raw bytes (409): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 02, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 00, 0c, 09, 00, 0f, 00, 15, 09, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 00, 10, 0d, 00, 13, 00, 2e, 0d, 02, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 00, 0c, 0d, 00, 0f, 00, 15, 0d, 01, 05, 00, 0f, 0d, 04, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 00, 0f, 1d, 02, 0c, 00, 13, 21, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
+Raw bytes (409): 0x[01, 01, 0a, 01, 05, 01, 09, 01, 0d, 11, 15, 1d, 21, 19, 1d, 19, 1d, 19, 1d, 27, 25, 1d, 21, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 02, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 01, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 05, 00, 0f, 01, 04, 05, 00, 0f, 01, 04, 05, 00, 0f, 01, 04, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 01, 04, 08, 00, 0f, 05, 01, 09, 00, 13, 02, 05, 09, 00, 13, 01, 05, 08, 00, 0f, 09, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 01, 03, 05, 00, 0f, 01, 01, 0c, 00, 13, 0d, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 11, 04, 05, 00, 0f, 11, 02, 0c, 00, 13, 15, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 19, 01, 0c, 00, 13, 1d, 01, 0d, 00, 17, 1d, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 21, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 25, 02, 05, 00, 0f, 25, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => $DIR/issue-84561.rs
 Number of expressions: 10
-- expression 0 operands: lhs = Counter(3), rhs = Counter(4)
-- expression 1 operands: lhs = Counter(3), rhs = Counter(5)
-- expression 2 operands: lhs = Counter(3), rhs = Counter(6)
-- expression 3 operands: lhs = Counter(7), rhs = Counter(8)
-- expression 4 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 5 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 6 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 7 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(12)
-- expression 9 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 4 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 5 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 6 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 7 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(9)
+- expression 9 operands: lhs = Counter(7), rhs = Counter(8)
 Number of file 0 mappings: 77
 - Code(Counter(0)) at (prev + 8, 1) to (start + 0, 11)
 - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16)
@@ -94,85 +94,85 @@ Number of file 0 mappings: 77
 - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12)
 - Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21)
 - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12)
-- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21)
-- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13)
-- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20)
-- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13)
-- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20)
-- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13)
-- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20)
-- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 15)
-- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 12)
-- Code(Counter(2)) at (prev + 0, 15) to (start + 0, 21)
-- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12)
+- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12)
+- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 48)
-- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13)
-- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20)
-- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13)
-- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20)
-- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13)
+- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20)
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 36)
 - Code(Zero) at (prev + 0, 41) to (start + 0, 48)
 - Code(Zero) at (prev + 0, 51) to (start + 0, 65)
 - Code(Zero) at (prev + 0, 75) to (start + 0, 90)
-- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
 - Code(Zero) at (prev + 5, 9) to (start + 0, 13)
 - Code(Zero) at (prev + 3, 9) to (start + 0, 16)
 - Code(Zero) at (prev + 2, 13) to (start + 0, 27)
 - Code(Zero) at (prev + 2, 13) to (start + 0, 28)
-- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 16)
-- Code(Counter(3)) at (prev + 0, 19) to (start + 0, 46)
-- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15)
-- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15)
-- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15)
-- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 12)
-- Code(Counter(3)) at (prev + 0, 15) to (start + 0, 21)
-- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(3)) at (prev + 4, 8) to (start + 0, 15)
-- Code(Counter(4)) at (prev + 1, 9) to (start + 0, 19)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16)
+- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46)
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 12)
+- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 4, 8) to (start + 0, 15)
+- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 19)
 - Code(Expression(0, Sub)) at (prev + 5, 9) to (start + 0, 19)
-    = (c3 - c4)
-- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15)
-- Code(Counter(5)) at (prev + 1, 9) to (start + 0, 19)
+    = (c0 - c1)
+- Code(Counter(0)) at (prev + 5, 8) to (start + 0, 15)
+- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 19)
 - Code(Zero) at (prev + 3, 13) to (start + 0, 29)
 - Code(Expression(1, Sub)) at (prev + 3, 9) to (start + 0, 19)
-    = (c3 - c5)
+    = (c0 - c2)
 - Code(Zero) at (prev + 3, 13) to (start + 0, 29)
-- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 15)
-- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 19)
-- Code(Counter(6)) at (prev + 1, 13) to (start + 0, 19)
+- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 15)
+- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 19)
+- Code(Counter(3)) at (prev + 1, 13) to (start + 0, 19)
 - Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = (c3 - c6)
-- Code(Counter(7)) at (prev + 4, 5) to (start + 0, 15)
-- Code(Counter(7)) at (prev + 2, 12) to (start + 0, 19)
-- Code(Counter(8)) at (prev + 1, 13) to (start + 0, 19)
+    = (c0 - c3)
+- Code(Counter(4)) at (prev + 4, 5) to (start + 0, 15)
+- Code(Counter(4)) at (prev + 2, 12) to (start + 0, 19)
+- Code(Counter(5)) at (prev + 1, 13) to (start + 0, 19)
 - Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = (c7 - c8)
+    = (c4 - c5)
 - Code(Expression(9, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c10 + c11)
-- Code(Counter(9)) at (prev + 1, 12) to (start + 0, 19)
-- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 23)
-- Code(Counter(10)) at (prev + 4, 13) to (start + 0, 19)
+    = (c7 + c8)
+- Code(Counter(6)) at (prev + 1, 12) to (start + 0, 19)
+- Code(Counter(7)) at (prev + 1, 13) to (start + 0, 23)
+- Code(Counter(7)) at (prev + 4, 13) to (start + 0, 19)
 - Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 23)
-    = (c9 - c10)
+    = (c6 - c7)
 - Code(Expression(7, Sub)) at (prev + 1, 20) to (start + 0, 27)
-    = (c9 - c10)
+    = (c6 - c7)
 - Code(Zero) at (prev + 1, 21) to (start + 0, 27)
 - Code(Expression(7, Sub)) at (prev + 2, 21) to (start + 0, 27)
-    = (c9 - c10)
-- Code(Counter(11)) at (prev + 4, 13) to (start + 0, 19)
+    = (c6 - c7)
+- Code(Counter(8)) at (prev + 4, 13) to (start + 0, 19)
 - Code(Expression(8, Sub)) at (prev + 3, 9) to (start + 0, 25)
-    = ((c10 + c11) - c12)
-- Code(Counter(12)) at (prev + 2, 5) to (start + 0, 15)
-- Code(Counter(12)) at (prev + 3, 9) to (start + 0, 34)
+    = ((c7 + c8) - c9)
+- Code(Counter(9)) at (prev + 2, 5) to (start + 0, 15)
+- Code(Counter(9)) at (prev + 3, 9) to (start + 0, 34)
 - Code(Zero) at (prev + 2, 5) to (start + 0, 15)
 - Code(Zero) at (prev + 3, 9) to (start + 0, 44)
 - Code(Zero) at (prev + 2, 1) to (start + 0, 2)
-Highest counter ID seen: c12
+Highest counter ID seen: c9
 
diff --git a/tests/crashes/117808.rs b/tests/crashes/117808.rs
deleted file mode 100644
index 2c727986dd0..00000000000
--- a/tests/crashes/117808.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@ known-bug: #117808
-//@ edition:2021
-//@ needs-rustc-debug-assertions
-
-use std::future::Future;
-
-fn hrc<R, F: for<'a> AsyncClosure<'a, (), R>>(f: F) -> F {
-    f
-}
-
-fn main() {
-    hrc(|x| async {});
-}
-
-trait AsyncClosure<'a, I, R>
-where
-    I: 'a,
-{
-}
-
-impl<'a, I, R, Fut, F> AsyncClosure<'a, I, R> for F
-where
-    I: 'a,
-    F: Fn(&'a I) -> Fut,
-    Fut: Future<Output = R> + Send + 'a,
-{
-}
diff --git a/tests/crashes/122904-2.rs b/tests/crashes/122904-2.rs
deleted file mode 100644
index db66b8625db..00000000000
--- a/tests/crashes/122904-2.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ known-bug: #122904
-trait T {}
-
-type Alias<'a> = impl T;
-
-struct S;
-impl<'a> T for &'a S {}
-
-#[define_opaque(Alias)]
-fn with_positive(fun: impl Fn(Alias<'_>)) {
-    with_positive(|&n| ());
-}
-
-#[define_opaque(Alias)]
-fn main(Alias<'_>) {
-    with_positive(|&a| ());
-}
diff --git a/tests/crashes/139556.rs b/tests/crashes/139556.rs
deleted file mode 100644
index 60dc8d7c3af..00000000000
--- a/tests/crashes/139556.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ known-bug: #139556
-
-trait T {}
-
-type Alias<'a> = impl T;
-
-struct S;
-impl<'a> T for &'a S {}
-
-#[define_opaque(Alias)]
-fn with_positive(fun: impl Fn(Alias<'_>)) {
-    with_positive(|&n| ());
-}
diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml b/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml
new file mode 100644
index 00000000000..3c61c12a84e
--- /dev/null
+++ b/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml
@@ -0,0 +1,12 @@
+cargo-features = ["profile-rustflags"]
+
+[package]
+name = "panic_scenarios"
+version = "0.1.0"
+edition = "2024"
+
+[lib]
+path = "lib.rs"
+
+[profile.release]
+rustflags = ["-Zmerge-functions=disabled", "-Zcodegen-source-order", "--emit=llvm-ir"]
diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs b/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs
new file mode 100644
index 00000000000..1e20da93ba8
--- /dev/null
+++ b/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs
@@ -0,0 +1,65 @@
+#![no_std]
+
+#[unsafe(no_mangle)]
+pub fn panic_noarg() {
+    // CHECK-LABEL: @panic_noarg(
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: tail call void @llvm.trap()
+    panic!();
+}
+
+#[unsafe(no_mangle)]
+pub fn panic_str() {
+    // CHECK-LABEL: @panic_str(
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: tail call void @llvm.trap()
+    panic!("ouch");
+}
+
+#[unsafe(no_mangle)]
+pub fn bounds_check(x: &[u8], idx: usize) -> &u8 {
+    // CHECK-LABEL: @bounds_check(
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: icmp ult
+    // CHECK-NEXT: br i1
+    // CHECK: bb1:
+    // CHECK-NEXT: getelementptr inbounds nuw i8
+    // CHECK-NEXT: ret ptr
+    // CHECK: panic:
+    // CHECK-NEXT: tail call void @llvm.trap()
+    &x[idx]
+}
+
+#[unsafe(no_mangle)]
+pub fn str_bounds_check(x: &str, idx: usize) -> &str {
+    // CHECK-LABEL: @str_bounds_check(
+    // CHECK-NOT: call
+    // CHECK: tail call void @llvm.trap()
+    // CHECK-NOT: call
+    &x[idx..]
+}
+
+#[unsafe(no_mangle)]
+pub fn unsigned_integer_div(x: u16, y: u16) -> u16 {
+    // CHECK-LABEL: @unsigned_integer_div(
+    // CHECK-NEXT: start:
+    // CHECK-NEXT: icmp eq i16
+    // CHECK-NEXT: br i1
+    // CHECK: bb1:
+    // CHECK-NEXT: udiv i16
+    // CHECK-NEXT: ret i16
+    // CHECK: panic:
+    // CHECK-NEXT: tail call void @llvm.trap()
+    x / y
+}
+
+#[unsafe(no_mangle)]
+pub fn refcell_already_borrowed() {
+    // CHECK-LABEL: @refcell_already_borrowed(
+    // CHECK-NOT: call
+    // CHECK: tail call void @llvm.trap()
+    // CHECK-NOT: call
+    let r = core::cell::RefCell::new(0u8);
+    let _guard = r.borrow_mut();
+    r.borrow_mut();
+}
diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs
new file mode 100644
index 00000000000..d7a7a8bfd8c
--- /dev/null
+++ b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs
@@ -0,0 +1,46 @@
+// This is a codegen test which checks that when code is compiled with panic=immediate-abort,
+// we get a `tail call void @llvm.trap()` in user code instead of a call into the standard
+// library's panic formatting code (such as panic_fmt) or one of the numerous panic outlining shims
+// (such as slice_index_fail).
+
+#![deny(warnings)]
+
+use run_make_support::{cargo, llvm_filecheck, path, rfs, target};
+
+fn main() {
+    let target_dir = path("target");
+
+    cargo()
+        .args(&[
+            "build",
+            "--release",
+            "--lib",
+            "--manifest-path",
+            "Cargo.toml",
+            "-Zbuild-std=core",
+            "--target",
+            &target(),
+        ])
+        .env("RUSTFLAGS", "-Zunstable-options -Cpanic=immediate-abort")
+        .env("CARGO_TARGET_DIR", &target_dir)
+        .env("RUSTC_BOOTSTRAP", "1")
+        // Visual Studio 2022 requires that the LIB env var be set so it can
+        // find the Windows SDK.
+        .env("LIB", std::env::var("LIB").unwrap_or_default())
+        .run();
+
+    let out_dir = target_dir.join(target()).join("release").join("deps");
+    let ir_file = rfs::read_dir(out_dir)
+        .find_map(|e| {
+            let path = e.unwrap().path();
+            let file_name = path.file_name().unwrap().to_str().unwrap();
+            if file_name.starts_with("panic_scenarios") && file_name.ends_with(".ll") {
+                Some(path)
+            } else {
+                None
+            }
+        })
+        .unwrap();
+
+    llvm_filecheck().patterns("lib.rs").input_file(ir_file).run();
+}
diff --git a/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml b/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml
new file mode 100644
index 00000000000..1e278d557c0
--- /dev/null
+++ b/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "hello"
+version = "0.1.0"
+edition = "2024"
diff --git a/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs b/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs
new file mode 100644
index 00000000000..3eeef38c962
--- /dev/null
+++ b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs
@@ -0,0 +1,39 @@
+// This test ensures we are able to compile and link a simple binary with panic=immediate-abort.
+// The test panic-immediate-abort-codegen checks that panic strategy produces the desired codegen,
+// but is based on compiling a library crate (which is the norm for codegen tests because it is
+// cleaner and more portable). So this test ensures that we didn't mix up a cfg or a compiler
+// implementation detail in a way that makes panic=immediate-abort encounter errors at link time.
+
+// Ideally this test would be run for most targets, but unfortunately:
+// This test is currently written using `fn main() {}` which requires std.
+// And since the default linker is only a linker for the host, we can't handle cross-compilation.
+// Both of these shortcomings could be addressed at the cost of making the test more complicated.
+//@ needs-target-std
+//@ ignore-cross-compile
+
+#![deny(warnings)]
+
+use run_make_support::{cargo, path, target};
+
+fn main() {
+    let target_dir = path("target");
+
+    cargo()
+        .current_dir("hello")
+        .args(&[
+            "build",
+            "--release",
+            "--manifest-path",
+            "Cargo.toml",
+            "-Zbuild-std",
+            "--target",
+            &target(),
+        ])
+        .env("RUSTFLAGS", "-Zunstable-options -Cpanic=immediate-abort")
+        .env("CARGO_TARGET_DIR", &target_dir)
+        .env("RUSTC_BOOTSTRAP", "1")
+        // Visual Studio 2022 requires that the LIB env var be set so it can
+        // find the Windows SDK.
+        .env("LIB", std::env::var("LIB").unwrap_or_default())
+        .run();
+}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-3.rs b/tests/run-make/crate-loading/dep-2-reexport.rs
index 07444511472..07444511472 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-3.rs
+++ b/tests/run-make/crate-loading/dep-2-reexport.rs
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/dependency-1.rs
index bfeabccf5c1..bfeabccf5c1 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-1.rs
+++ b/tests/run-make/crate-loading/dependency-1.rs
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/dependency-2.rs
index 682d1ff64b8..682d1ff64b8 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-2.rs
+++ b/tests/run-make/crate-loading/dependency-2.rs
diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs
index 6ad456e3e3e..8f257786123 100644
--- a/tests/run-make/crate-loading/rmake.rs
+++ b/tests/run-make/crate-loading/rmake.rs
@@ -6,12 +6,9 @@
 use run_make_support::{diff, rust_lib_name, rustc};
 
 fn main() {
-    rustc().input("multiple-dep-versions-1.rs").run();
-    rustc().input("multiple-dep-versions-2.rs").extra_filename("2").metadata("2").run();
-    rustc()
-        .input("multiple-dep-versions-3.rs")
-        .extern_("dependency", rust_lib_name("dependency2"))
-        .run();
+    rustc().input("dependency-1.rs").run();
+    rustc().input("dependency-2.rs").extra_filename("2").metadata("2").run();
+    rustc().input("dep-2-reexport.rs").extern_("dependency", rust_lib_name("dependency2")).run();
 
     let out = rustc()
         .input("multiple-dep-versions.rs")
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
index 9ea706af503..b0c40dd171d 100644
--- a/tests/run-make/linker-warning/rmake.rs
+++ b/tests/run-make/linker-warning/rmake.rs
@@ -61,7 +61,6 @@ fn main() {
         diff()
             .expected_file("short-error.txt")
             .actual_text("(linker error)", out.stderr())
-            .normalize(r#"/rustc[^/_-]*/"#, "/rustc/")
             .normalize("libpanic_abort", "libpanic_unwind")
             .normalize(
                 regex::escape(
diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs
index 1b30c538b5e..e9d09e359c6 100644
--- a/tests/run-make/musl-default-linking/rmake.rs
+++ b/tests/run-make/musl-default-linking/rmake.rs
@@ -4,7 +4,7 @@ use run_make_support::{rustc, serde_json};
 // Per https://github.com/rust-lang/compiler-team/issues/422,
 // we should be trying to move these targets to dynamically link
 // musl libc by default.
-//@ needs-llvm-components: aarch64 arm mips powerpc x86
+//@ needs-llvm-components: aarch64 arm powerpc x86
 static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[
     "aarch64-unknown-linux-musl",
     "arm-unknown-linux-musleabi",
@@ -14,7 +14,6 @@ static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[
     "armv7-unknown-linux-musleabihf",
     "i586-unknown-linux-musl",
     "i686-unknown-linux-musl",
-    "mips64el-unknown-linux-muslabi64",
     "powerpc64le-unknown-linux-musl",
     "x86_64-unknown-linux-musl",
 ];
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
index 0a2186b0953..2ac5fdee063 100644
--- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
@@ -1,12 +1,14 @@
 // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication
 // code (PAC), a useful hashing measure for verifying that pointers have not been modified.
 // This test checks that compilation and execution is successful when this feature is activated,
-// with some of its possible extra arguments (bti, pac-ret, leaf) when doing LTO.
+// with some of its possible extra arguments (bti, gcs, pac-ret, leaf) when doing LTO.
 // See https://github.com/rust-lang/rust/pull/88354
 
 //@ needs-force-clang-based-tests
 //@ only-aarch64
 // Reason: branch protection is not supported on other architectures
+//@ ignore-apple
+// Reason: XCode needs updating to support gcs
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
 
@@ -19,7 +21,7 @@ fn main() {
     clang()
         .arg("-v")
         .lto("thin")
-        .arg("-mbranch-protection=bti+pac-ret+b-key+leaf")
+        .arg("-mbranch-protection=bti+gcs+pac-ret+b-key+leaf")
         .arg("-c")
         .out_exe("test.o")
         .input("test.c")
@@ -30,7 +32,7 @@ fn main() {
         .opt_level("2")
         .linker(&env_var("CLANG"))
         .link_arg("-fuse-ld=lld")
-        .arg("-Zbranch-protection=bti,pac-ret,leaf")
+        .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf")
         .input("test.rs")
         .output("test.bin")
         .run();
diff --git a/tests/run-make/pointer-auth-link-with-c/rmake.rs b/tests/run-make/pointer-auth-link-with-c/rmake.rs
index a4d7454e575..1ddcb79d64f 100644
--- a/tests/run-make/pointer-auth-link-with-c/rmake.rs
+++ b/tests/run-make/pointer-auth-link-with-c/rmake.rs
@@ -1,11 +1,13 @@
 // `-Z branch protection` is an unstable compiler feature which adds pointer-authentication
 // code (PAC), a useful hashing measure for verifying that pointers have not been modified.
 // This test checks that compilation and execution is successful when this feature is activated,
-// with some of its possible extra arguments (bti, pac-ret, pc, leaf, b-key).
+// with some of its possible extra arguments (bti, gcs, pac-ret, pc, leaf, b-key).
 // See https://github.com/rust-lang/rust/pull/88354
 
 //@ only-aarch64
 // Reason: branch protection is not supported on other architectures
+//@ ignore-apple
+// Reason: XCode needs updating to support gcs
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
 
@@ -13,17 +15,17 @@ use run_make_support::{build_native_static_lib, cc, is_windows_msvc, llvm_ar, ru
 
 fn main() {
     build_native_static_lib("test");
-    rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run();
+    rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run();
     run("test");
     cc().arg("-v")
         .arg("-c")
         .out_exe("test")
         .input("test.c")
-        .arg("-mbranch-protection=bti+pac-ret+leaf")
+        .arg("-mbranch-protection=bti+gcs+pac-ret+leaf")
         .run();
     let obj_file = if is_windows_msvc() { "test.obj" } else { "test" };
     llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run();
-    rustc().arg("-Zbranch-protection=bti,pac-ret,leaf").input("test.rs").run();
+    rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run();
     run("test");
 
     // FIXME: +pc was only recently added to LLVM
diff --git a/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs
new file mode 100644
index 00000000000..0b1e1948d5f
--- /dev/null
+++ b/tests/run-make/rustdoc-merge-no-input-finalize/rmake.rs
@@ -0,0 +1,28 @@
+// Running --merge=finalize without an input crate root should not trigger ICE.
+// Issue: https://github.com/rust-lang/rust/issues/146646
+
+//@ needs-target-std
+
+use run_make_support::{path, rustdoc};
+
+fn main() {
+    let out_dir = path("out");
+    let merged_dir = path("merged");
+    let parts_out_dir = path("parts");
+    rustdoc()
+        .input("sierra.rs")
+        .out_dir(&out_dir)
+        .arg("-Zunstable-options")
+        .arg(format!("--parts-out-dir={}", parts_out_dir.display()))
+        .arg("--merge=none")
+        .run();
+    assert!(parts_out_dir.join("crate-info").exists());
+
+    let output = rustdoc()
+        .arg("-Zunstable-options")
+        .out_dir(&out_dir)
+        .arg(format!("--include-parts-dir={}", parts_out_dir.display()))
+        .arg("--merge=finalize")
+        .run();
+    output.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug.");
+}
diff --git a/tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs b/tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs
new file mode 100644
index 00000000000..f8fc48341ed
--- /dev/null
+++ b/tests/run-make/rustdoc-merge-no-input-finalize/sierra.rs
@@ -0,0 +1 @@
+pub struct Sierra;
diff --git a/tests/rustdoc-gui/search-title.goml b/tests/rustdoc-gui/search-title.goml
index 83321a05f2b..5808ed845a3 100644
--- a/tests/rustdoc-gui/search-title.goml
+++ b/tests/rustdoc-gui/search-title.goml
@@ -20,3 +20,15 @@ assert-document-property: {"title": '"another one" Search - Rust'}
 press-key: "Escape"
 
 assert-document-property: {"title": |title|}
+
+// check that all.html does it correctly, too.
+go-to: "file://" + |DOC_PATH| + "/test_docs/all.html"
+assert-document-property: {"title": "List of all items in this crate"}
+call-function: ("perform-search", {"query": "verify"})
+assert-document-property: {"title": '"verify" Search - Rust'}
+
+// check that index.html does it correctly, too.
+go-to: "file://" + |DOC_PATH| + "/index.html"
+assert-document-property: {"title": "Index of crates"}
+call-function: ("perform-search", {"query": "verify"})
+assert-document-property: {"title": '"verify" Search - Rust'}
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index 42f2fbd93b1..c0771583ab6 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -1,3 +1,4 @@
+//@ compile-flags: --enable-index-page -Z unstable-options
 //! The point of this crate is to be able to have enough different "kinds" of
 //! documentation generated so we can test each different features.
 #![doc(html_playground_url="https://play.rust-lang.org/")]
@@ -459,10 +460,10 @@ pub fn safe_fn() {}
 
 #[repr(C)]
 pub struct WithGenerics<T: TraitWithNoDocblocks, S = String, E = WhoLetTheDogOut, P = i8> {
-    s: S,
-    t: T,
-    e: E,
-    p: P,
+    pub s: S,
+    pub t: T,
+    pub e: E,
+    pub p: P,
 }
 
 pub struct StructWithPublicUndocumentedFields {
diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs
new file mode 100644
index 00000000000..d7efc201e7e
--- /dev/null
+++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs
@@ -0,0 +1,25 @@
+// this test ensures that bad HTML with multiline tags doesn't cause an ICE
+// regression test for https://github.com/rust-lang/rust/issues/146890
+#[deny(rustdoc::invalid_html_tags)]
+
+/// <TABLE
+/// BORDER>
+/// <TR
+/// >
+/// <TH
+//~^ ERROR: unclosed HTML tag `TH`
+/// >key
+/// </TD
+//~^ ERROR: unopened HTML tag `TD`
+/// >
+/// <TH
+//~^ ERROR: unclosed HTML tag `TH`
+/// >value
+/// </TD
+//~^ ERROR: unopened HTML tag `TD`
+/// >
+/// </TR
+/// >
+/// </TABLE
+/// >
+pub fn foo() {}
diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr
new file mode 100644
index 00000000000..64a82b3a952
--- /dev/null
+++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.stderr
@@ -0,0 +1,38 @@
+error: unopened HTML tag `TD`
+  --> $DIR/invalid-html-tags-ice-146890.rs:12:5
+   |
+LL |   /// </TD
+   |  _____^
+LL | |
+LL | | /// >
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/invalid-html-tags-ice-146890.rs:3:8
+   |
+LL | #[deny(rustdoc::invalid_html_tags)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unopened HTML tag `TD`
+  --> $DIR/invalid-html-tags-ice-146890.rs:18:5
+   |
+LL |   /// </TD
+   |  _____^
+LL | |
+LL | | /// >
+   | |_____^
+
+error: unclosed HTML tag `TH`
+  --> $DIR/invalid-html-tags-ice-146890.rs:9:5
+   |
+LL | /// <TH
+   |     ^^^
+
+error: unclosed HTML tag `TH`
+  --> $DIR/invalid-html-tags-ice-146890.rs:15:5
+   |
+LL | /// <TH
+   |     ^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/rustdoc/attribute-rendering.rs b/tests/rustdoc/attribute-rendering.rs
deleted file mode 100644
index fb40d0a9887..00000000000
--- a/tests/rustdoc/attribute-rendering.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![crate_name = "foo"]
-
-//@ has 'foo/fn.f.html'
-//@ has - //*[@'class="code-attribute"]' '#[unsafe(export_name = "f")]'
-//@ has - //*[@'class="rust item-decl"]' 'pub fn f()'
-#[unsafe(export_name = "\
-f")]
-pub fn f() {}
diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc/attributes.rs
index 33e4e31bec6..429a42a7252 100644
--- a/tests/rustdoc/attributes.rs
+++ b/tests/rustdoc/attributes.rs
@@ -9,6 +9,18 @@ pub extern "C" fn f() {}
 #[unsafe(export_name = "bar")]
 pub extern "C" fn g() {}
 
+//@ has foo/fn.escape_special.html '//*[@class="code-attribute"]' \
+//                                 '#[unsafe(export_name = "\n\"\n")]'
+#[unsafe(export_name = "\n\"
+")]
+pub extern "C" fn escape_special() {}
+
+// issue: <https://github.com/rust-lang/rust/issues/142835>
+//@ has foo/fn.escape_html.html '//*[@class="code-attribute"]' \
+//                              '#[unsafe(export_name = "<script>alert()</script>")]'
+#[unsafe(export_name = "<script>alert()</script>")]
+pub extern "C" fn escape_html() {}
+
 //@ has foo/fn.example.html '//*[@class="code-attribute"]' '#[unsafe(link_section = ".text")]'
 #[unsafe(link_section = ".text")]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc/auxiliary/ext-repr.rs b/tests/rustdoc/auxiliary/ext-repr.rs
new file mode 100644
index 00000000000..25acaa49449
--- /dev/null
+++ b/tests/rustdoc/auxiliary/ext-repr.rs
@@ -0,0 +1,5 @@
+#[repr(i8)]
+pub enum ReprI8 {
+    Var0,
+    Var1,
+}
diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc/inline_cross/attributes.rs
index 4747f8ad67c..1657b7bdc8f 100644
--- a/tests/rustdoc/inline_cross/attributes.rs
+++ b/tests/rustdoc/inline_cross/attributes.rs
@@ -1,7 +1,20 @@
+// Ensure that we render attributes on inlined cross-crate re-exported items.
+// issue: <https://github.com/rust-lang/rust/issues/144004>
+
 //@ aux-crate:attributes=attributes.rs
 //@ edition:2021
 #![crate_name = "user"]
 
-//@ has 'user/struct.NonExhaustive.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]'
+//@ has 'user/fn.no_mangle.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
+pub use attributes::no_mangle;
+
+//@ has 'user/fn.link_section.html' '//pre[@class="rust item-decl"]' \
+//                                  '#[unsafe(link_section = ".here")]'
+pub use attributes::link_section;
+
+//@ has 'user/fn.export_name.html' '//pre[@class="rust item-decl"]' \
+//                                 '#[unsafe(export_name = "exonym")]'
+pub use attributes::export_name;
+
+//@ has 'user/struct.NonExhaustive.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
 pub use attributes::NonExhaustive;
diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc/inline_cross/auxiliary/attributes.rs
index c6f155d4ba5..6068d385585 100644
--- a/tests/rustdoc/inline_cross/auxiliary/attributes.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/attributes.rs
@@ -1,2 +1,11 @@
+#[unsafe(no_mangle)]
+pub fn no_mangle() {}
+
+#[unsafe(link_section = ".here")]
+pub fn link_section() {}
+
+#[unsafe(export_name = "exonym")]
+pub fn export_name() {}
+
 #[non_exhaustive]
 pub struct NonExhaustive;
diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs
deleted file mode 100644
index 0211e1a8658..00000000000
--- a/tests/rustdoc/inline_cross/auxiliary/repr.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-#![feature(repr_simd)]
-
-#[repr(C, align(8))]
-pub struct ReprC {
-    field: u8,
-}
-#[repr(simd, packed(2))]
-pub struct ReprSimd {
-    field: [u8; 1],
-}
-#[repr(transparent)]
-pub struct ReprTransparent {
-    pub field: u8,
-}
-#[repr(isize)]
-pub enum ReprIsize {
-    Bla,
-}
-#[repr(u8)]
-pub enum ReprU8 {
-    Bla,
-}
-
-#[repr(transparent)] // private
-pub struct ReprTransparentPrivField {
-    field: u32, // non-1-ZST field
-}
-
-#[repr(transparent)] // public
-pub struct ReprTransparentPriv1ZstFields {
-    marker0: Marker,
-    pub main: u64, // non-1-ZST field
-    marker1: Marker,
-}
-
-#[repr(transparent)] // private
-pub struct ReprTransparentPrivFieldPub1ZstFields {
-    main: [u16; 0], // non-1-ZST field
-    pub marker: Marker,
-}
-
-pub struct Marker; // 1-ZST
diff --git a/tests/rustdoc/inline_cross/repr.rs b/tests/rustdoc/inline_cross/repr.rs
deleted file mode 100644
index d13e560b8d7..00000000000
--- a/tests/rustdoc/inline_cross/repr.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Regression test for <https://github.com/rust-lang/rust/issues/110698>.
-// This test ensures that the re-exported items still have the `#[repr(...)]` attribute.
-
-//@ aux-build:repr.rs
-
-#![crate_name = "foo"]
-
-extern crate repr;
-
-//@ has 'foo/struct.ReprC.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
-pub use repr::ReprC;
-//@ has 'foo/struct.ReprSimd.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
-pub use repr::ReprSimd;
-//@ has 'foo/struct.ReprTransparent.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparent;
-//@ has 'foo/enum.ReprIsize.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
-pub use repr::ReprIsize;
-//@ has 'foo/enum.ReprU8.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]'
-pub use repr::ReprU8;
-
-// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
-// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
-// field is public in case all fields are 1-ZST fields.
-
-//@ has 'foo/struct.ReprTransparentPrivField.html'
-//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparentPrivField;
-
-//@ has 'foo/struct.ReprTransparentPriv1ZstFields.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparentPriv1ZstFields;
-
-//@ has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html'
-//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparentPrivFieldPub1ZstFields;
diff --git a/tests/rustdoc/jump-to-def-assoc-items.rs b/tests/rustdoc/jump-to-def-assoc-items.rs
new file mode 100644
index 00000000000..8cbf9906283
--- /dev/null
+++ b/tests/rustdoc/jump-to-def-assoc-items.rs
@@ -0,0 +1,54 @@
+// This test ensures that patterns also get a link generated.
+
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+
+#![crate_name = "foo"]
+
+//@ has 'src/foo/jump-to-def-assoc-items.rs.html'
+
+pub trait Trait {
+    type T;
+}
+pub trait Another {
+    type T;
+    const X: u32;
+}
+
+pub struct Foo;
+
+impl Foo {
+    pub fn new() -> Self { Foo }
+}
+
+pub struct C;
+
+impl C {
+    pub fn wat() {}
+}
+
+pub struct Bar;
+impl Trait for Bar {
+    type T = Foo;
+}
+impl Another for Bar {
+    type T = C;
+    const X: u32 = 12;
+}
+
+pub fn bar() {
+    //@ has - '//a[@href="#20"]' 'new'
+    <Bar as Trait>::T::new();
+    //@ has - '//a[@href="#26"]' 'wat'
+    <Bar as Another>::T::wat();
+
+    match 12u32 {
+        //@ has - '//a[@href="#14"]' 'X'
+        <Bar as Another>::X => {}
+        _ => {}
+    }
+}
+
+pub struct Far {
+        //@ has - '//a[@href="#10"]' 'T'
+    x: <Bar as Trait>::T,
+}
diff --git a/tests/rustdoc/jump-to-def-ice-assoc-types.rs b/tests/rustdoc/jump-to-def-ice-assoc-types.rs
new file mode 100644
index 00000000000..9915c53668f
--- /dev/null
+++ b/tests/rustdoc/jump-to-def-ice-assoc-types.rs
@@ -0,0 +1,20 @@
+// This test ensures that associated types don't crash rustdoc jump to def.
+
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+
+
+#![crate_name = "foo"]
+
+//@ has 'src/foo/jump-to-def-ice-assoc-types.rs.html'
+
+pub trait Trait {
+    type Node;
+}
+
+pub fn y<G: Trait>() {
+    struct X<G>(G);
+
+    impl<G: Trait> Trait for X<G> {
+        type Node = G::Node;
+    }
+}
diff --git a/tests/rustdoc/jump-to-def-ice.rs b/tests/rustdoc/jump-to-def-ice.rs
new file mode 100644
index 00000000000..5578b9af3d7
--- /dev/null
+++ b/tests/rustdoc/jump-to-def-ice.rs
@@ -0,0 +1,24 @@
+// This test ensures that items with no body don't panic when generating
+// jump to def links.
+
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+
+#![crate_name = "foo"]
+
+//@ has 'src/foo/jump-to-def-ice.rs.html'
+
+pub trait A {
+    type T;
+    type U;
+}
+
+impl A for () {
+    type T = Self::U;
+    type U = ();
+}
+
+pub trait C {
+    type X;
+}
+
+pub struct F<T: C>(pub T::X);
diff --git a/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs
index 61856978773..55e59f23b6f 100644
--- a/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs
+++ b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs
@@ -8,7 +8,7 @@
 pub struct Bar;
 
 impl std::default::Default for Bar {
-    //@ has - '//a[@href="#20-22"]' 'Self::new'
+    //@ has - '//a[@href="#20-22"]' 'new'
     fn default() -> Self {
         Self::new()
     }
@@ -16,7 +16,7 @@ impl std::default::Default for Bar {
 
 //@ has - '//a[@href="#8"]' 'Bar'
 impl Bar {
-     //@ has - '//a[@href="#24-26"]' 'Self::bar'
+     //@ has - '//a[@href="#24-26"]' 'bar'
      pub fn new()-> Self {
          Self::bar()
      }
diff --git a/tests/rustdoc/jump-to-def/jump-to-def-pats.rs b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs
index 147902b44cf..852eba208db 100644
--- a/tests/rustdoc/jump-to-def/jump-to-def-pats.rs
+++ b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs
@@ -30,13 +30,13 @@ pub fn foo() -> Result<(), ()> {
 impl<T, E> fmt::Display for MyEnum<T, E> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            //@ has - '//a[@href="#12"]' 'Self::Ok'
+            //@ has - '//a[@href="#12"]' 'Ok'
             Self::Ok(_) => f.write_str("MyEnum::Ok"),
-            //@ has - '//a[@href="#13"]' 'MyEnum::Err'
+            //@ has - '//a[@href="#13"]' 'Err'
             MyEnum::Err(_) => f.write_str("MyEnum::Err"),
-            //@ has - '//a[@href="#14"]' 'Self::Some'
+            //@ has - '//a[@href="#14"]' 'Some'
             Self::Some(_) => f.write_str("MyEnum::Some"),
-            //@ has - '//a[@href="#15"]' 'Self::None'
+            //@ has - '//a[@href="#15"]' 'None'
             Self::None => f.write_str("MyEnum::None"),
         }
     }
@@ -45,7 +45,7 @@ impl<T, E> fmt::Display for MyEnum<T, E> {
 impl X {
     fn p(&self) -> &str {
         match self {
-            //@ has - '//a[@href="#19"]' 'Self::A'
+            //@ has - '//a[@href="#19"]' 'A'
             Self::A => "X::A",
         }
     }
diff --git a/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs
index e2f530425f0..1d6d6b8d18f 100644
--- a/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs
+++ b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs
@@ -21,9 +21,10 @@ pub fn bar2<T: Read>(readable: T) {
 }
 
 pub fn bar() {
-    //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'AtomicIsize::new'
+    //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html"]' 'AtomicIsize'
+    //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'new'
     let _ = AtomicIsize::new(0);
-    //@ has - '//a[@href="#48"]' 'local_private'
+    //@ has - '//a[@href="#49"]' 'local_private'
     local_private();
 }
 
@@ -39,7 +40,7 @@ pub fn macro_call() -> Result<(), ()> {
 }
 
 pub fn variant() {
-    //@ has - '//a[@href="{{channel}}/core/cmp/enum.Ordering.html#variant.Less"]' 'Ordering::Less'
+    //@ has - '//a[@href="{{channel}}/core/cmp/enum.Ordering.html#variant.Less"]' 'Less'
     let _ = Ordering::Less;
     //@ has - '//a[@href="{{channel}}/core/marker/struct.PhantomData.html"]' 'PhantomData'
     let _: PhantomData::<usize> = PhantomData;
diff --git a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs b/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs
deleted file mode 100644
index 96fa8209cde..00000000000
--- a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-#[unsafe(no_mangle)]
-pub fn f0() {}
-
-#[unsafe(link_section = ".here")]
-pub fn f1() {}
-
-#[unsafe(export_name = "f2export")]
-pub fn f2() {}
-
-#[repr(u8)]
-pub enum T0 { V1 }
-
-#[non_exhaustive]
-pub enum T1 {}
diff --git a/tests/rustdoc/reexport/private-mod-override-reexport.rs b/tests/rustdoc/reexport/private-mod-override-reexport.rs
new file mode 100644
index 00000000000..849acc5fdae
--- /dev/null
+++ b/tests/rustdoc/reexport/private-mod-override-reexport.rs
@@ -0,0 +1,13 @@
+// https://github.com/rust-lang/rust/issues/60926
+#![crate_name = "foo"]
+
+mod m1 {
+    pub mod m2 {
+        pub struct Foo;
+    }
+}
+
+pub use m1::*;
+use crate::m1::m2;
+
+//@ count foo/index.html '//a[@class="mod"]' 0
diff --git a/tests/rustdoc/reexport/reexport-attrs.rs b/tests/rustdoc/reexport/reexport-attrs.rs
deleted file mode 100644
index aec0a11c0c6..00000000000
--- a/tests/rustdoc/reexport/reexport-attrs.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ aux-build: reexports-attrs.rs
-
-#![crate_name = "foo"]
-
-extern crate reexports_attrs;
-
-//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
-pub use reexports_attrs::f0;
-
-//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".here")]'
-pub use reexports_attrs::f1;
-
-//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "f2export")]'
-pub use reexports_attrs::f2;
-
-//@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]'
-pub use reexports_attrs::T0;
-
-//@ has 'foo/enum.T1.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
-pub use reexports_attrs::T1;
diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc/repr.rs
index f4f683b3d81..1e8fad6ec0a 100644
--- a/tests/rustdoc/repr.rs
+++ b/tests/rustdoc/repr.rs
@@ -1,29 +1,163 @@
-// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
-// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
-// field is public in case all fields are 1-ZST fields.
+// Test the rendering of `#[repr]` on ADTs.
+#![feature(repr_simd)] // only used for the `ReprSimd` test case
+
+// Check the "local case" (HIR cleaning) //
+
+// Don't render the default repr which is `Rust`.
+//@ has 'repr/struct.ReprDefault.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]'
+pub struct ReprDefault;
+
+// Don't render the `Rust` repr — even if given explicitly — since it's the default.
+//@ has 'repr/struct.ReprRust.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]'
+#[repr(Rust)] // omitted
+pub struct ReprRust;
+
+//@ has 'repr/struct.ReprCPubFields.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
+#[repr(C)] // public
+pub struct ReprCPubFields {
+    pub a: u32,
+    pub b: u32,
+}
+
+//@ has 'repr/struct.ReprCPrivField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
+#[repr(C)] // private...
+pub struct ReprCPrivField {
+    a: u32, // ...since this is private
+    pub b: u32,
+}
+
+//@ has 'repr/enum.ReprIsize.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
+#[repr(isize)] // public
+pub enum ReprIsize {
+    Bla,
+}
+
+//@ has 'repr/enum.ReprU32HiddenVariant.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32)]'
+#[repr(u32)] // private...
+pub enum ReprU32HiddenVariant {
+    #[doc(hidden)]
+    Hidden, // ...since this is hidden
+    Public,
+}
+
+//@ has 'repr/struct.ReprAlignHiddenField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(align(4))]'
+#[repr(align(4))] // private...
+pub struct ReprAlignHiddenField {
+    #[doc(hidden)]
+    pub hidden: i16, // ...since this field is hidden
+}
+
+//@ has 'repr/struct.ReprSimd.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
+#[repr(simd, packed(2))] // public
+pub struct ReprSimd {
+    pub field: [u8; 1],
+}
+
+//@ has 'repr/enum.ReprU32Align.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32, align(8))]'
+#[repr(u32, align(8))] // public
+pub enum ReprU32Align {
+    Variant(u16),
+}
+
+//@ has 'repr/enum.ReprCHiddenVariantField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
+#[repr(C)] // private...
+pub enum ReprCHiddenVariantField {
+    Variant { #[doc(hidden)] field: () }, //...since this field is hidden
+}
 
 //@ has 'repr/struct.ReprTransparentPrivField.html'
 //@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-#[repr(transparent)] // private
+#[repr(transparent)] // private...
 pub struct ReprTransparentPrivField {
-    field: u32, // non-1-ZST field
+    field: u32, // ...since the non-1-ZST field is private
 }
 
 //@ has 'repr/struct.ReprTransparentPriv1ZstFields.html'
 //@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-#[repr(transparent)] // public
+#[repr(transparent)] // public...
 pub struct ReprTransparentPriv1ZstFields {
     marker0: Marker,
-    pub main: u64, // non-1-ZST field
+    pub main: u64, // ...since the non-1-ZST field is public and visible
     marker1: Marker,
+} // the two private 1-ZST fields don't matter
+
+//@ has 'repr/struct.ReprTransparentPrivFieldPub1ZstField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // private...
+pub struct ReprTransparentPrivFieldPub1ZstField {
+    main: [u16; 0], // ...since the non-1-ZST field is private
+    pub marker: Marker, // this public 1-ZST field doesn't matter
 }
 
 //@ has 'repr/struct.ReprTransparentPub1ZstField.html'
 //@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-#[repr(transparent)] // public
+#[repr(transparent)] // public...
 pub struct ReprTransparentPub1ZstField {
-    marker0: Marker,
-    pub marker1: Marker,
+    marker0: Marker, // ...since we don't have a non-1-ZST field...
+    pub marker1: Marker, // ...and this field is public and visible
+}
+
+//@ has 'repr/struct.ReprTransparentUnitStruct.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public
+pub struct ReprTransparentUnitStruct;
+
+//@ has 'repr/enum.ReprTransparentEnumUnitVariant.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public
+pub enum ReprTransparentEnumUnitVariant {
+    Variant,
+}
+
+//@ has 'repr/enum.ReprTransparentEnumHiddenUnitVariant.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // private
+pub enum ReprTransparentEnumHiddenUnitVariant {
+    #[doc(hidden)] Variant(u32),
+}
+
+//@ has 'repr/enum.ReprTransparentEnumPub1ZstField.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public...
+pub enum ReprTransparentEnumPub1ZstField {
+    Variant {
+        field: u64, // ...since the non-1-ZST field is public
+        #[doc(hidden)]
+        marker: Marker, // this hidden 1-ZST field doesn't matter
+    },
+}
+
+//@ has 'repr/enum.ReprTransparentEnumHidden1ZstField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // private...
+pub enum ReprTransparentEnumHidden1ZstField {
+    Variant {
+        #[doc(hidden)]
+        field: u64, // ...since the non-1-ZST field is public
+    },
 }
 
 struct Marker; // 1-ZST
+
+// Check the "extern case" (middle cleaning) //
+
+// Internally, HIR and middle cleaning share `#[repr]` rendering.
+// Thus we'll only test the very basics in this section.
+
+//@ aux-build: ext-repr.rs
+extern crate ext_repr as ext;
+
+// Regression test for <https://github.com/rust-lang/rust/issues/110698>.
+//@ has 'repr/enum.ReprI8.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(i8)]'
+pub use ext::ReprI8;
diff --git a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs
index d701b88bf9f..a7b944fa2f6 100644
--- a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs
+++ b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs
@@ -34,7 +34,7 @@ fn babar() {}
 // The 5 links to line 23 and the line 23 itself.
 //@ count - '//pre[@class="rust"]//a[@href="#23"]' 6
 //@ has - '//pre[@class="rust"]//a[@href="../../source_code/struct.SourceCode.html"]' \
-//        'source_code::SourceCode'
+//        'SourceCode'
 pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
     let x = 12;
     let y: Foo = Foo;
diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr
index 124013f89af..82faba8d167 100644
--- a/tests/ui/asm/powerpc/bad-reg.aix64.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,7 +201,7 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -173,7 +209,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:70:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -181,7 +217,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:78:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -189,7 +225,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -197,7 +233,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -205,7 +241,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -213,7 +249,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -221,7 +305,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -229,12 +313,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 34 previous errors
+error: aborting due to 46 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
index b11c946f80d..fac70ea77cb 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,67 +201,67 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:57:18
+  --> $DIR/bad-reg.rs:53:18
    |
 LL |         asm!("", in("v0") v32x4); // requires altivec
    |                  ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:59:18
+  --> $DIR/bad-reg.rs:55:18
    |
 LL |         asm!("", out("v0") v32x4); // requires altivec
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:61:18
+  --> $DIR/bad-reg.rs:57:18
    |
 LL |         asm!("", in("v0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("v0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:67:18
+  --> $DIR/bad-reg.rs:63:18
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:70:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:73:26
+  --> $DIR/bad-reg.rs:69:26
    |
 LL |         asm!("/* {} */", in(vreg) v32x4); // requires altivec
    |                          ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:75:26
+  --> $DIR/bad-reg.rs:71:26
    |
 LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    |                          ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:78:26
+  --> $DIR/bad-reg.rs:74:26
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:81:26
+  --> $DIR/bad-reg.rs:77:26
    |
 LL |         asm!("/* {} */", out(vreg) _); // requires altivec
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -233,7 +269,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -241,7 +277,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -249,7 +285,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -257,7 +341,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -265,12 +349,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 41 previous errors
+error: aborting due to 53 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
index a93b2b018df..42a59448f42 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,7 +201,7 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:61:27
+  --> $DIR/bad-reg.rs:57:27
    |
 LL |         asm!("", in("v0") v64x2); // requires vsx
    |                           ^^^^^
@@ -173,7 +209,7 @@ LL |         asm!("", in("v0") v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:64:28
+  --> $DIR/bad-reg.rs:60:28
    |
 LL |         asm!("", out("v0") v64x2); // requires vsx
    |                            ^^^^^
@@ -181,7 +217,7 @@ LL |         asm!("", out("v0") v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -189,7 +225,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:70:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -197,7 +233,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:75:35
+  --> $DIR/bad-reg.rs:71:35
    |
 LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    |                                   ^^^^^
@@ -205,7 +241,7 @@ LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:78:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -213,7 +249,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -221,7 +257,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -229,7 +265,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -237,7 +273,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -245,7 +329,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -253,12 +337,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 37 previous errors
+error: aborting due to 49 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
index 124013f89af..82faba8d167 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,7 +201,7 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -173,7 +209,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:70:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -181,7 +217,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:78:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -189,7 +225,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -197,7 +233,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -205,7 +241,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -213,7 +249,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -221,7 +305,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -229,12 +313,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 34 previous errors
+error: aborting due to 46 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs
index 5598f837960..21ea451934e 100644
--- a/tests/ui/asm/powerpc/bad-reg.rs
+++ b/tests/ui/asm/powerpc/bad-reg.rs
@@ -45,10 +45,6 @@ fn f() {
         //~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
         asm!("", out("fp") _);
         //~^ ERROR invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-        asm!("", out("lr") _);
-        //~^ ERROR invalid register `lr`: the link register cannot be used as an operand for inline asm
-        asm!("", out("ctr") _);
-        //~^ ERROR invalid register `ctr`: the counter register cannot be used as an operand for inline asm
         asm!("", out("vrsave") _);
         //~^ ERROR invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
 
@@ -108,6 +104,32 @@ fn f() {
         //~| ERROR type `i32` cannot be used with this register class
         asm!("/* {} */", out(cr) _);
         //~^ ERROR can only be used as a clobber
+        // ctr
+        asm!("", out("ctr") _); // ok
+        asm!("", in("ctr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("", out("ctr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", in(ctr) x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", out(ctr) _);
+        //~^ ERROR can only be used as a clobber
+        // lr
+        asm!("", out("lr") _); // ok
+        asm!("", in("lr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("", out("lr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", in(lr) x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", out(lr) _);
+        //~^ ERROR can only be used as a clobber
         // xer
         asm!("", out("xer") _); // ok
         asm!("", in("xer") x);
diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs
new file mode 100644
index 00000000000..e5c1f47b9e0
--- /dev/null
+++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Zdeduplicate-diagnostics=yes
+
+// Regression test for #146467.
+#![feature(inherent_associated_types)]
+//~^ WARN the feature `inherent_associated_types` is incomplete
+
+struct Foo<T>(T);
+
+impl<'a> Foo<fn(&())> {
+    //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait
+    type Assoc = &'a ();
+}
+
+fn foo(_: for<'a> fn(Foo<fn(&'a ())>::Assoc)) {}
+//~^ ERROR mismatched types
+//~| ERROR higher-ranked subtype error
+fn main() {}
diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr
new file mode 100644
index 00000000000..4c0726d4ddc
--- /dev/null
+++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr
@@ -0,0 +1,34 @@
+warning: the feature `inherent_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/hr-do-not-blame-outlives-static-ice.rs:4:12
+   |
+LL | #![feature(inherent_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/hr-do-not-blame-outlives-static-ice.rs:9:6
+   |
+LL | impl<'a> Foo<fn(&())> {
+   |      ^^ unconstrained lifetime parameter
+
+error[E0308]: mismatched types
+  --> $DIR/hr-do-not-blame-outlives-static-ice.rs:14:11
+   |
+LL | fn foo(_: for<'a> fn(Foo<fn(&'a ())>::Assoc)) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected struct `Foo<for<'a> fn(&'a ())>`
+              found struct `Foo<for<'a> fn(&'a ())>`
+
+error: higher-ranked subtype error
+  --> $DIR/hr-do-not-blame-outlives-static-ice.rs:14:1
+   |
+LL | fn foo(_: for<'a> fn(Foo<fn(&'a ())>::Assoc)) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0207, E0308.
+For more information about an error, try `rustc --explain E0207`.
diff --git a/tests/ui/attributes/invalid_macro_export_argument.allow.stderr b/tests/ui/attributes/invalid_macro_export_argument.allow.stderr
new file mode 100644
index 00000000000..162b315b072
--- /dev/null
+++ b/tests/ui/attributes/invalid_macro_export_argument.allow.stderr
@@ -0,0 +1,40 @@
+Future incompatibility report: Future breakage diagnostic:
+warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:7:1
+   |
+LL | #[macro_export(hello, world)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
+Future breakage diagnostic:
+warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:14:1
+   |
+LL | #[macro_export(not_local_inner_macros)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
+Future breakage diagnostic:
+warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:31:1
+   |
+LL | #[macro_export()]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
+Future breakage diagnostic:
+warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:38:1
+   |
+LL | #[macro_export("blah")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
diff --git a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
index 9d44bd162c7..ad225ae187b 100644
--- a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
+++ b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
@@ -1,26 +1,103 @@
-error: `#[macro_export]` can only take 1 or 0 arguments
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:7:1
    |
 LL | #[macro_export(hello, world)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 note: the lint level is defined here
   --> $DIR/invalid_macro_export_argument.rs:4:24
    |
 LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: invalid `#[macro_export]` argument
-  --> $DIR/invalid_macro_export_argument.rs:13:16
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:14:1
    |
 LL | #[macro_export(not_local_inner_macros)]
-   |                ^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:31:1
+   |
+LL | #[macro_export()]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: invalid `#[macro_export]` argument
-  --> $DIR/invalid_macro_export_argument.rs:33:16
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:38:1
    |
 LL | #[macro_export("blah")]
-   |                ^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
+error: aborting due to 4 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:7:1
+   |
+LL | #[macro_export(hello, world)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+note: the lint level is defined here
+  --> $DIR/invalid_macro_export_argument.rs:4:24
+   |
+LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:14:1
+   |
+LL | #[macro_export(not_local_inner_macros)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+note: the lint level is defined here
+  --> $DIR/invalid_macro_export_argument.rs:4:24
+   |
+LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+Future breakage diagnostic:
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:31:1
+   |
+LL | #[macro_export()]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+note: the lint level is defined here
+  --> $DIR/invalid_macro_export_argument.rs:4:24
+   |
+LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/invalid_macro_export_argument.rs:38:1
+   |
+LL | #[macro_export("blah")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+note: the lint level is defined here
+  --> $DIR/invalid_macro_export_argument.rs:4:24
+   |
+LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/attributes/invalid_macro_export_argument.rs b/tests/ui/attributes/invalid_macro_export_argument.rs
index c5fe39d062a..05a40913434 100644
--- a/tests/ui/attributes/invalid_macro_export_argument.rs
+++ b/tests/ui/attributes/invalid_macro_export_argument.rs
@@ -5,13 +5,15 @@
 #![cfg_attr(allow, allow(invalid_macro_export_arguments))]
 
 #[macro_export(hello, world)]
-//[deny]~^ ERROR `#[macro_export]` can only take 1 or 0 arguments
+//[deny]~^ ERROR valid forms for the attribute are
+//[deny]~| WARN this was previously accepted
 macro_rules! a {
     () => ()
 }
 
 #[macro_export(not_local_inner_macros)]
-//[deny]~^ ERROR invalid `#[macro_export]` argument
+//[deny]~^ ERROR valid forms for the attribute are
+//[deny]~| WARN this was previously accepted
 macro_rules! b {
     () => ()
 }
@@ -20,18 +22,22 @@ macro_rules! b {
 macro_rules! c {
     () => ()
 }
+
 #[macro_export(local_inner_macros)]
 macro_rules! d {
     () => ()
 }
 
 #[macro_export()]
+//[deny]~^ ERROR valid forms for the attribute are
+//[deny]~| WARN this was previously accepted
 macro_rules! e {
     () => ()
 }
 
 #[macro_export("blah")]
-//[deny]~^ ERROR invalid `#[macro_export]` argument
+//[deny]~^ ERROR valid forms for the attribute are
+//[deny]~| WARN this was previously accepted
 macro_rules! f {
     () => ()
 }
diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs
index 932aaf7a9e2..820484aa015 100644
--- a/tests/ui/attributes/malformed-attrs.rs
+++ b/tests/ui/attributes/malformed-attrs.rs
@@ -185,8 +185,7 @@ extern "C" {
 #[forbid]
 //~^ ERROR malformed
 #[debugger_visualizer]
-//~^ ERROR invalid argument
-//~| ERROR malformed `debugger_visualizer` attribute input
+//~^ ERROR malformed `debugger_visualizer` attribute input
 #[automatically_derived = 18]
 //~^ ERROR malformed
 mod yooo {
@@ -211,7 +210,7 @@ extern crate wloop;
 //~^ ERROR can't find crate for `wloop` [E0463]
 
 #[macro_export = 18]
-//~^ ERROR malformed `macro_export` attribute input
+//~^ ERROR valid forms for the attribute are
 #[allow_internal_unsafe = 1]
 //~^ ERROR malformed
 //~| ERROR allow_internal_unsafe side-steps the unsafe_code lint
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index b85864b401e..70ab3fb13c4 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -22,7 +22,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
    |           ++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0463]: can't find crate for `wloop`
-  --> $DIR/malformed-attrs.rs:210:1
+  --> $DIR/malformed-attrs.rs:209:1
    |
 LL | extern crate wloop;
    | ^^^^^^^^^^^^^^^^^^^ can't find crate
@@ -156,44 +156,20 @@ LL | #[forbid(lint1, lint2, ...)]
 LL | #[forbid(lint1, lint2, lint3, reason = "...")]
    |         +++++++++++++++++++++++++++++++++++++
 
-error: malformed `debugger_visualizer` attribute input
-  --> $DIR/malformed-attrs.rs:187:1
-   |
-LL | #[debugger_visualizer]
-   | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
-
 error: malformed `thread_local` attribute input
-  --> $DIR/malformed-attrs.rs:202:1
+  --> $DIR/malformed-attrs.rs:201:1
    |
 LL | #[thread_local()]
    | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]`
 
 error: malformed `no_link` attribute input
-  --> $DIR/malformed-attrs.rs:206:1
+  --> $DIR/malformed-attrs.rs:205:1
    |
 LL | #[no_link()]
    | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/items/extern-crates.html#the-no_link-attribute>
 
-error: malformed `macro_export` attribute input
-  --> $DIR/malformed-attrs.rs:213:1
-   |
-LL | #[macro_export = 18]
-   | ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope>
-help: the following are the possible correct uses
-   |
-LL - #[macro_export = 18]
-LL + #[macro_export(local_inner_macros)]
-   |
-LL - #[macro_export = 18]
-LL + #[macro_export]
-   |
-
 error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
   --> $DIR/malformed-attrs.rs:98:1
    |
@@ -213,7 +189,7 @@ LL | #[proc_macro_derive]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint
-  --> $DIR/malformed-attrs.rs:215:1
+  --> $DIR/malformed-attrs.rs:214:1
    |
 LL | #[allow_internal_unsafe = 1]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -242,16 +218,6 @@ LL | #[doc]
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
 
-error: invalid argument
-  --> $DIR/malformed-attrs.rs:187:1
-   |
-LL | #[debugger_visualizer]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: expected: `natvis_file = "..."`
-   = note: OR
-   = note: expected: `gdb_script_file = "..."`
-
 error[E0539]: malformed `export_name` attribute input
   --> $DIR/malformed-attrs.rs:29:1
    |
@@ -701,8 +667,19 @@ LL |     #[linkage = "external"]
    |               ++++++++++++
    = and 5 other candidates
 
+error[E0539]: malformed `debugger_visualizer` attribute input
+  --> $DIR/malformed-attrs.rs:187:1
+   |
+LL | #[debugger_visualizer]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
+
 error[E0565]: malformed `automatically_derived` attribute input
-  --> $DIR/malformed-attrs.rs:190:1
+  --> $DIR/malformed-attrs.rs:189:1
    |
 LL | #[automatically_derived = 18]
    | ^^^^^^^^^^^^^^^^^^^^^^^^----^
@@ -711,7 +688,7 @@ LL | #[automatically_derived = 18]
    | help: must be of the form: `#[automatically_derived]`
 
 error[E0565]: malformed `non_exhaustive` attribute input
-  --> $DIR/malformed-attrs.rs:196:1
+  --> $DIR/malformed-attrs.rs:195:1
    |
 LL | #[non_exhaustive = 1]
    | ^^^^^^^^^^^^^^^^^---^
@@ -720,13 +697,19 @@ LL | #[non_exhaustive = 1]
    | help: must be of the form: `#[non_exhaustive]`
 
 error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]`
-  --> $DIR/malformed-attrs.rs:208:1
+  --> $DIR/malformed-attrs.rs:207:1
    |
 LL | #[macro_use = 1]
    | ^^^^^^^^^^^^^^^^
 
+error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+  --> $DIR/malformed-attrs.rs:212:1
+   |
+LL | #[macro_export = 18]
+   | ^^^^^^^^^^^^^^^^^^^^
+
 error[E0565]: malformed `allow_internal_unsafe` attribute input
-  --> $DIR/malformed-attrs.rs:215:1
+  --> $DIR/malformed-attrs.rs:214:1
    |
 LL | #[allow_internal_unsafe = 1]
    | ^^^^^^^^^^^^^^^^^^^^^^^^---^
@@ -810,7 +793,7 @@ LL | #[ignore()]
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
-  --> $DIR/malformed-attrs.rs:222:1
+  --> $DIR/malformed-attrs.rs:221:1
    |
 LL | #[ignore = 1]
    | ^^^^^^^^^^^^^
@@ -829,7 +812,7 @@ LL |     #[coroutine = 63] || {}
    = note: expected unit type `()`
               found coroutine `{coroutine@$DIR/malformed-attrs.rs:110:23: 110:25}`
 
-error: aborting due to 77 previous errors; 3 warnings emitted
+error: aborting due to 76 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`.
@@ -881,7 +864,7 @@ LL | #[ignore()]
 
 Future breakage diagnostic:
 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
-  --> $DIR/malformed-attrs.rs:222:1
+  --> $DIR/malformed-attrs.rs:221:1
    |
 LL | #[ignore = 1]
    | ^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr
index 6b2e628e12e..39fee52a909 100644
--- a/tests/ui/check-cfg/cfg-crate-features.stderr
+++ b/tests/ui/check-cfg/cfg-crate-features.stderr
@@ -24,7 +24,7 @@ warning: unexpected `cfg` condition value: `does_not_exist`
 LL | #![cfg(not(target(os = "does_not_exist")))]
    |                   ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, and `tvos` and 11 more
+   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, and `trusty` and 12 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr
index 989a01f2244..4b5fc91c7eb 100644
--- a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr
+++ b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr
@@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE`
 LL |     cfg_macro::my_lib_macro_value!();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `panic` are: `abort` and `unwind`
+   = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind`
    = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
    = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg
    = help: the macro `cfg_macro::my_lib_macro_value` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro`
diff --git a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr
index 95d10e014f3..0d99d061d28 100644
--- a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr
+++ b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr
@@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE`
 LL |     cfg_macro::my_lib_macro_value!();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `panic` are: `abort` and `unwind`
+   = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind`
    = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate
    = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 6490fc63fd7..e62f741b302 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -80,7 +80,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     panic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `panic` are: `abort` and `unwind`
+   = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind`
    = 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`
@@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_os = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
+   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = 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`
@@ -274,7 +274,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux`
    |                   |
    |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
+   = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 28 warnings emitted
diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg b/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg
index 1cedbf75e4b..7ffbc64b074 100644
--- a/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg
+++ b/tests/ui/codemap_tests/huge_multispan_highlight.ascii.svg
@@ -1,7 +1,7 @@
-<svg width="743px" height="758px" xmlns="http://www.w3.org/2000/svg">
+<svg width="740px" height="758px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-012 { fill: #5555FF }
     .container {
diff --git a/tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg b/tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg
index 36a33b74042..5f1fcdb3d50 100644
--- a/tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg
+++ b/tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg
@@ -1,7 +1,7 @@
-<svg width="743px" height="758px" xmlns="http://www.w3.org/2000/svg">
+<svg width="740px" height="758px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-012 { fill: #5555FF }
     .container {
diff --git a/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs
new file mode 100644
index 00000000000..38479d9070b
--- /dev/null
+++ b/tests/ui/coercion/no_local_for_coerced_const-issue-143671.rs
@@ -0,0 +1,46 @@
+//@ run-pass
+
+#![feature(unsize)]
+#![feature(coerce_unsized)]
+
+use std::fmt::Display;
+use std::marker::Unsize;
+use std::ops::CoerceUnsized;
+use std::rc::Weak;
+
+#[repr(transparent)]
+struct X<'a, T: ?Sized> {
+    f: &'a T,
+}
+
+impl<'a, T: ?Sized> Drop for X<'a, T> {
+    fn drop(&mut self) {
+        panic!()
+    }
+}
+
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<X<'a, U>> for X<'a, T> where
+    &'a T: CoerceUnsized<&'a U>
+{
+}
+
+const Y: X<'static, i32> = X { f: &0 };
+
+fn main() {
+    let _: [X<'static, dyn Display>; 0] = [Y; 0];
+    coercion_on_weak_in_const();
+    coercion_on_weak_as_cast();
+}
+
+fn coercion_on_weak_in_const() {
+    const X: Weak<i32> = Weak::new();
+    const Y: [Weak<dyn Send>; 0] = [X; 0];
+    let _ = Y;
+}
+
+fn coercion_on_weak_as_cast() {
+    const Y: X<'static, i32> = X { f: &0 };
+    // What happens in the following code is that
+    // a constant is explicitly coerced into
+    let _a: [X<'static, dyn Display>; 0] = [Y as X<'static, dyn Display>; 0];
+}
diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr
index a5ae5c726da..134dbba0d63 100644
--- a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr
+++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr
@@ -7,7 +7,7 @@ LL |
 LL | struct A([u8]);
    |          ---- this field does not implement `ConstParamTy_`
    |
-note: the `ConstParamTy_` impl for `[u8]` requires that `unstable feature: `unsized_const_params``
+note: the `ConstParamTy_` impl for `[u8]` requires that `feature(unsized_const_params) is enabled`
   --> $DIR/unsized_field-1.rs:10:10
    |
 LL | struct A([u8]);
@@ -22,7 +22,7 @@ LL |
 LL | struct B(&'static [u8]);
    |          ------------- this field does not implement `ConstParamTy_`
    |
-note: the `ConstParamTy_` impl for `&'static [u8]` requires that `unstable feature: `unsized_const_params``
+note: the `ConstParamTy_` impl for `&'static [u8]` requires that `feature(unsized_const_params) is enabled`
   --> $DIR/unsized_field-1.rs:14:10
    |
 LL | struct B(&'static [u8]);
@@ -37,7 +37,7 @@ LL |
 LL | struct D(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>);
    |          ---------------------------------------------------------- this field does not implement `ConstParamTy_`
    |
-note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `unstable feature: `unsized_const_params``
+note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `feature(unsized_const_params) is enabled`
   --> $DIR/unsized_field-1.rs:21:10
    |
 LL | struct D(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>);
diff --git a/tests/ui/const-generics/forbid-non-structural_match-types.stderr b/tests/ui/const-generics/forbid-non-structural_match-types.stderr
index 8ef629329f1..94afded9469 100644
--- a/tests/ui/const-generics/forbid-non-structural_match-types.stderr
+++ b/tests/ui/const-generics/forbid-non-structural_match-types.stderr
@@ -6,8 +6,8 @@ LL | struct D<const X: C>;
    |
 help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct
    |
-LL - struct C;
 LL + #[derive(ConstParamTy, PartialEq, Eq)]
+LL | struct C;
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/const-generics/issue-80471.stderr b/tests/ui/const-generics/issue-80471.stderr
index 8cf3d68e5d6..fff2eb53cf1 100644
--- a/tests/ui/const-generics/issue-80471.stderr
+++ b/tests/ui/const-generics/issue-80471.stderr
@@ -4,10 +4,10 @@ error[E0741]: `Nat` must implement `ConstParamTy` to be used as the type of a co
 LL | fn foo<const N: Nat>() {}
    |                 ^^^
    |
-help: add `#[derive(ConstParamTy)]` to the struct
+help: add `#[derive(ConstParamTy)]` to the enum
    |
-LL - enum Nat {
 LL + #[derive(ConstParamTy)]
+LL | enum Nat {
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/const-generics/issues/issue-97278.stderr b/tests/ui/const-generics/issues/issue-97278.stderr
index 4894ddb7b8d..21a5fc94032 100644
--- a/tests/ui/const-generics/issues/issue-97278.stderr
+++ b/tests/ui/const-generics/issues/issue-97278.stderr
@@ -4,10 +4,10 @@ error[E0741]: `Bar` must implement `ConstParamTy` to be used as the type of a co
 LL | fn test<const BAR: Bar>() {}
    |                    ^^^
    |
-help: add `#[derive(ConstParamTy)]` to the struct
+help: add `#[derive(ConstParamTy)]` to the enum
    |
-LL - enum Bar {
 LL + #[derive(ConstParamTy)]
+LL | enum Bar {
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs
index 91646842624..851f3996cd1 100644
--- a/tests/ui/consts/const-eval/ub-nonnull.rs
+++ b/tests/ui/consts/const-eval/ub-nonnull.rs
@@ -57,4 +57,8 @@ const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
     mem::transmute((0_usize, meta))
 };
 
+static S: u32 = 0; // just a static to construct a maybe-null pointer off of
+const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) };
+//~^ ERROR invalid value
+
 fn main() {}
diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr
index 91c82efbc5e..e4486e3c500 100644
--- a/tests/ui/consts/const-eval/ub-nonnull.stderr
+++ b/tests/ui/consts/const-eval/ub-nonnull.stderr
@@ -9,7 +9,7 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
                HEX_DUMP
            }
 
-error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC1 which is only 1 byte from the end of the allocation
+error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC2 which is only 1 byte from the end of the allocation
   --> $DIR/ub-nonnull.rs:22:29
    |
 LL |     let out_of_bounds_ptr = &ptr[255];
@@ -37,7 +37,7 @@ LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) };
                HEX_DUMP
            }
 
-error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
+error[E0080]: reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
   --> $DIR/ub-nonnull.rs:36:38
    |
 LL | const UNINIT: NonZero<u8> = unsafe { MaybeUninit { uninit: () }.init };
@@ -80,6 +80,17 @@ LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe {
                HEX_DUMP
            }
 
-error: aborting due to 8 previous errors
+error[E0080]: constructing invalid value: encountered a maybe-null pointer, but expected something that is definitely non-zero
+  --> $DIR/ub-nonnull.rs:61:1
+   |
+LL | const MAYBE_NULL_PTR: NonNull<()> = unsafe { mem::transmute((&raw const S).wrapping_add(4)) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
+   |
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs
index d8e5102fcbe..a5fdde1f9a4 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.rs
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs
@@ -4,7 +4,7 @@
 //@ normalize-stderr: "([0-9a-f][0-9a-f] |__ |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 //@ dont-require-annotations: NOTE
 //@ normalize-stderr: "0x[0-9](\.\.|\])" -> "0x%$1"
-
+#![feature(rustc_attrs)]
 #![allow(invalid_value)]
 
 use std::mem;
@@ -27,6 +27,11 @@ const NULL: &u16 = unsafe { mem::transmute(0usize) };
 const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
 //~^ ERROR invalid value
 
+const MAYBE_NULL_BOX: Box<()> = unsafe { mem::transmute({
+//~^ ERROR maybe-null
+    let ref_ = &0u8;
+    (ref_ as *const u8).wrapping_add(10)
+}) };
 
 // It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`,
 // but that would fail to compile; so we ended up breaking user code that would
@@ -57,7 +62,12 @@ const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
 //~^ ERROR invalid value
 const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
 //~^ ERROR invalid value
-
+const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({
+//~^ ERROR invalid value
+    fn fun() {}
+    let ptr = fun as fn();
+    (ptr as *const u8).wrapping_add(10)
+}) };
 
 const UNALIGNED_READ: () = unsafe {
     let x = &[0u8; 4];
@@ -65,5 +75,14 @@ const UNALIGNED_READ: () = unsafe {
     ptr.read(); //~ ERROR accessing memory
 };
 
+// Check the general case of a pointer value not falling into the scalar valid range.
+#[rustc_layout_scalar_valid_range_start(1000)]
+pub struct High {
+    pointer: *const (),
+}
+static S: u32 = 0; // just a static to construct a pointer with unknown absolute address
+const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) };
+//~^ ERROR invalid value
+
 
 fn main() {}
diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
index c45f66c2925..349a98f11be 100644
--- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr
+++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr
@@ -42,8 +42,19 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
                HEX_DUMP
            }
 
+error[E0080]: constructing invalid value: encountered a maybe-null box
+  --> $DIR/ub-ref-ptr.rs:30:1
+   |
+LL | const MAYBE_NULL_BOX: Box<()> = unsafe { mem::transmute({
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
+   |
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-ref-ptr.rs:34:1
+  --> $DIR/ub-ref-ptr.rs:39:1
    |
 LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE` failed here
@@ -52,7 +63,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-ref-ptr.rs:37:39
+  --> $DIR/ub-ref-ptr.rs:42:39
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_SLICE` failed here
@@ -61,13 +72,13 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant encountered
-  --> $DIR/ub-ref-ptr.rs:37:38
+  --> $DIR/ub-ref-ptr.rs:42:38
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: unable to turn pointer into integer
-  --> $DIR/ub-ref-ptr.rs:40:86
+  --> $DIR/ub-ref-ptr.rs:45:86
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^ evaluation of `REF_AS_USIZE_BOX_SLICE` failed here
@@ -76,13 +87,13 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 note: erroneous constant encountered
-  --> $DIR/ub-ref-ptr.rs:40:85
+  --> $DIR/ub-ref-ptr.rs:45:85
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
    |                                                                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0080]: constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance)
-  --> $DIR/ub-ref-ptr.rs:43:1
+  --> $DIR/ub-ref-ptr.rs:48:1
    |
 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -93,7 +104,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
            }
 
 error[E0080]: constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance)
-  --> $DIR/ub-ref-ptr.rs:46:1
+  --> $DIR/ub-ref-ptr.rs:51:1
    |
 LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -103,8 +114,8 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
                HEX_DUMP
            }
 
-error[E0080]: reading memory at ALLOC3[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
-  --> $DIR/ub-ref-ptr.rs:49:41
+error[E0080]: reading memory at ALLOC6[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
+  --> $DIR/ub-ref-ptr.rs:54:41
    |
 LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_PTR` failed here
@@ -114,7 +125,7 @@ LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
            }
 
 error[E0080]: constructing invalid value: encountered null pointer, but expected a function pointer
-  --> $DIR/ub-ref-ptr.rs:52:1
+  --> $DIR/ub-ref-ptr.rs:57:1
    |
 LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -124,8 +135,8 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
                HEX_DUMP
            }
 
-error[E0080]: reading memory at ALLOC4[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
-  --> $DIR/ub-ref-ptr.rs:54:38
+error[E0080]: reading memory at ALLOC7[0x%..0x%], but memory is uninitialized at [0x%..0x%], and this operation requires initialized memory
+  --> $DIR/ub-ref-ptr.rs:59:38
    |
 LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNINIT_FN_PTR` failed here
@@ -135,7 +146,7 @@ LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
            }
 
 error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
-  --> $DIR/ub-ref-ptr.rs:56:1
+  --> $DIR/ub-ref-ptr.rs:61:1
    |
 LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -145,8 +156,8 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
                HEX_DUMP
            }
 
-error[E0080]: constructing invalid value: encountered ALLOC2<imm>, but expected a function pointer
-  --> $DIR/ub-ref-ptr.rs:58:1
+error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected a function pointer
+  --> $DIR/ub-ref-ptr.rs:63:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
    | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
@@ -156,12 +167,34 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
                HEX_DUMP
            }
 
+error[E0080]: constructing invalid value: encountered ALLOC4+0xa, but expected a function pointer
+  --> $DIR/ub-ref-ptr.rs:65:1
+   |
+LL | const MAYBE_NULL_FN_PTR: fn() = unsafe { mem::transmute({
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
+   |
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
 error[E0080]: accessing memory based on pointer with alignment 1, but alignment 4 is required
-  --> $DIR/ub-ref-ptr.rs:65:5
+  --> $DIR/ub-ref-ptr.rs:75:5
    |
 LL |     ptr.read();
    |     ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here
 
-error: aborting due to 15 previous errors
+error[E0080]: constructing invalid value: encountered a pointer with unknown absolute address, but expected something that is definitely greater or equal to 1000
+  --> $DIR/ub-ref-ptr.rs:84:1
+   |
+LL | const INVALID_VALUE_PTR: High = unsafe { mem::transmute(&S) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
+   |
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error: aborting due to 18 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const_transmute_type_id7.rs b/tests/ui/consts/const_transmute_type_id7.rs
new file mode 100644
index 00000000000..73b8187a800
--- /dev/null
+++ b/tests/ui/consts/const_transmute_type_id7.rs
@@ -0,0 +1,16 @@
+//! Ensure a decent error message for maybe-null references.
+//! (see <https://github.com/rust-lang/rust/issues/146748>)
+
+// Strip out raw byte dumps to make comparison platform-independent:
+//@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
+//@ normalize-stderr: "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
+
+#![feature(const_trait_impl, const_cmp)]
+
+use std::any::TypeId;
+use std::mem::transmute;
+
+const A: [&(); 16 / size_of::<*const ()>()] = unsafe { transmute(TypeId::of::<i32>()) };
+//~^ERROR: maybe-null
+
+fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id7.stderr b/tests/ui/consts/const_transmute_type_id7.stderr
new file mode 100644
index 00000000000..664975831f4
--- /dev/null
+++ b/tests/ui/consts/const_transmute_type_id7.stderr
@@ -0,0 +1,14 @@
+error[E0080]: constructing invalid value at [0]: encountered a maybe-null reference
+  --> $DIR/const_transmute_type_id7.rs:13:1
+   |
+LL | const A: [&(); 16 / size_of::<*const ()>()] = unsafe { transmute(TypeId::of::<i32>()) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
+   |
+   = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/promoted_const_call2.rs b/tests/ui/consts/promoted_const_call2.rs
index f332cd18cea..62391f098e5 100644
--- a/tests/ui/consts/promoted_const_call2.rs
+++ b/tests/ui/consts/promoted_const_call2.rs
@@ -4,7 +4,6 @@ pub const C: () = {
     let _: &'static _ = &id(&String::new());
     //~^ ERROR: temporary value dropped while borrowed
     //~| ERROR: temporary value dropped while borrowed
-    //~| ERROR: destructor of `String` cannot be evaluated at compile-time
 };
 
 fn main() {
diff --git a/tests/ui/consts/promoted_const_call2.stderr b/tests/ui/consts/promoted_const_call2.stderr
index bdb43385d20..e62458d1a6a 100644
--- a/tests/ui/consts/promoted_const_call2.stderr
+++ b/tests/ui/consts/promoted_const_call2.stderr
@@ -18,16 +18,8 @@ LL |     let _: &'static _ = &id(&String::new());
    |            |                 creates a temporary value which is freed while still in use
    |            type annotation requires that borrow lasts for `'static`
 
-error[E0493]: destructor of `String` cannot be evaluated at compile-time
-  --> $DIR/promoted_const_call2.rs:4:30
-   |
-LL |     let _: &'static _ = &id(&String::new());
-   |                              ^^^^^^^^^^^^^ - value is dropped here
-   |                              |
-   |                              the destructor for this type cannot be evaluated in constants
-
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promoted_const_call2.rs:11:26
+  --> $DIR/promoted_const_call2.rs:10:26
    |
 LL |     let _: &'static _ = &id(&String::new());
    |            ----------    ^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
@@ -38,7 +30,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promoted_const_call2.rs:11:30
+  --> $DIR/promoted_const_call2.rs:10:30
    |
 LL |     let _: &'static _ = &id(&String::new());
    |            ----------        ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -46,7 +38,6 @@ LL |     let _: &'static _ = &id(&String::new());
    |            |                 creates a temporary value which is freed while still in use
    |            type annotation requires that borrow lasts for `'static`
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0493, E0716.
-For more information about an error, try `rustc --explain E0493`.
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr
index 65e4dc22c28..62c5c527641 100644
--- a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr
+++ b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr
@@ -15,8 +15,8 @@ LL | struct Foo<const T: CompileTimeSettings>;
    |
 help: add `#[derive(ConstParamTy)]` to the struct
    |
-LL - struct CompileTimeSettings {
 LL + #[derive(ConstParamTy)]
+LL | struct CompileTimeSettings {
    |
 
 error[E0741]: `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter
@@ -27,8 +27,8 @@ LL | impl<const T: CompileTimeSettings> Foo<T> {
    |
 help: add `#[derive(ConstParamTy)]` to the struct
    |
-LL - struct CompileTimeSettings {
 LL + #[derive(ConstParamTy)]
+LL | struct CompileTimeSettings {
    |
 
 error: aborting due to 2 previous errors; 1 warning emitted
diff --git a/tests/ui/coroutine/copy-fast-path-query-cycle.rs b/tests/ui/coroutine/copy-fast-path-query-cycle.rs
new file mode 100644
index 00000000000..644cba0d47a
--- /dev/null
+++ b/tests/ui/coroutine/copy-fast-path-query-cycle.rs
@@ -0,0 +1,40 @@
+//@ edition: 2024
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for #146813. We previously used a pseudo-canonical
+// query during HIR typeck which caused a query cycle when looking at the
+// witness of a coroutine.
+
+use std::future::Future;
+
+trait ConnectMiddleware {}
+
+trait ConnectHandler: Sized {
+    fn with<M>(self, _: M) -> impl ConnectHandler
+    where
+        M: ConnectMiddleware,
+    {
+        LayeredConnectHandler
+    }
+}
+
+struct LayeredConnectHandler;
+impl ConnectHandler for LayeredConnectHandler {}
+impl<F> ConnectHandler for F where F: FnOnce() {}
+
+impl<F, Fut> ConnectMiddleware for F
+where
+    F: FnOnce() -> Fut,
+    Fut: Future<Output = ()> + Send,
+{
+}
+
+pub async fn fails() {
+    { || {} }
+        .with(async || ())
+        .with(async || ())
+        .with(async || ());
+}
+fn main() {}
diff --git a/tests/crashes/122630.rs b/tests/ui/coroutine/moved-twice.rs
index e66624431c5..72b83e274c9 100644
--- a/tests/crashes/122630.rs
+++ b/tests/ui/coroutine/moved-twice.rs
@@ -1,22 +1,27 @@
-//@ known-bug: #122630
+//! Regression test for #122630
 //@ compile-flags: -Zvalidate-mir
 
+#![feature(coroutines, coroutine_trait, yield_expr)]
+
 use std::ops::Coroutine;
 
 const FOO_SIZE: usize = 1024;
 struct Foo([u8; FOO_SIZE]);
 
 impl Drop for Foo {
-    fn move_before_yield_with_noop() -> impl Coroutine<Yield = ()> {}
+    fn drop(&mut self) {}
 }
 
 fn overlap_move_points() -> impl Coroutine<Yield = ()> {
-    static || {
+    #[coroutine] static || {
         let first = Foo([0; FOO_SIZE]);
         yield;
         let second = first;
         yield;
         let second = first;
+        //~^ ERROR: use of moved value: `first` [E0382]
         yield;
     }
 }
+
+fn main() {}
diff --git a/tests/ui/coroutine/moved-twice.stderr b/tests/ui/coroutine/moved-twice.stderr
new file mode 100644
index 00000000000..2b21f6c59f0
--- /dev/null
+++ b/tests/ui/coroutine/moved-twice.stderr
@@ -0,0 +1,24 @@
+error[E0382]: use of moved value: `first`
+  --> $DIR/moved-twice.rs:21:22
+   |
+LL |         let first = Foo([0; FOO_SIZE]);
+   |             ----- move occurs because `first` has type `Foo`, which does not implement the `Copy` trait
+LL |         yield;
+LL |         let second = first;
+   |                      ----- value moved here
+LL |         yield;
+LL |         let second = first;
+   |                      ^^^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/moved-twice.rs:9:1
+   |
+LL | struct Foo([u8; FOO_SIZE]);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         let second = first;
+   |                      ----- you could clone this value
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/diagnostic-flags/colored-session-opt-error.svg b/tests/ui/diagnostic-flags/colored-session-opt-error.svg
index 69f452f29f3..136c6fa5628 100644
--- a/tests/ui/diagnostic-flags/colored-session-opt-error.svg
+++ b/tests/ui/diagnostic-flags/colored-session-opt-error.svg
@@ -1,7 +1,7 @@
-<svg width="750px" height="74px" xmlns="http://www.w3.org/2000/svg">
+<svg width="740px" height="74px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-yellow { fill: #AA5500 }
     .container {
       padding: 0 10px;
diff --git a/tests/ui/diagnostic-flags/terminal_urls.rs b/tests/ui/diagnostic-flags/terminal_urls.rs
index 3c74e992395..631512ab579 100644
--- a/tests/ui/diagnostic-flags/terminal_urls.rs
+++ b/tests/ui/diagnostic-flags/terminal_urls.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Zterminal-urls=yes
+//@ compile-flags: -Zterminal-urls=yes --error-format=human --color=always
 fn main() {
-    let () = 4; //~ ERROR
+    let () = 4;
 }
diff --git a/tests/ui/diagnostic-flags/terminal_urls.stderr b/tests/ui/diagnostic-flags/terminal_urls.stderr
deleted file mode 100644
index e5dfcdf6431..00000000000
--- a/tests/ui/diagnostic-flags/terminal_urls.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[]8;;https://doc.rust-lang.org/error_codes/E0308.htmlE0308]8;;]: mismatched types
-  --> $DIR/terminal_urls.rs:3:9
-   |
-LL |     let () = 4;
-   |         ^^   - this expression has type `{integer}`
-   |         |
-   |         expected integer, found `()`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/diagnostic-flags/terminal_urls.svg b/tests/ui/diagnostic-flags/terminal_urls.svg
new file mode 100644
index 00000000000..fcb65637c4a
--- /dev/null
+++ b/tests/ui/diagnostic-flags/terminal_urls.svg
@@ -0,0 +1,48 @@
+<svg width="740px" height="236px" xmlns="http://www.w3.org/2000/svg">
+  <style>
+    .fg { fill: #AAAAAA }
+    .bg { fill: #000000 }
+    .fg-ansi256-009 { fill: #FF5555 }
+    .fg-ansi256-012 { fill: #5555FF }
+    .container {
+      padding: 0 10px;
+      line-height: 18px;
+    }
+    .bold { font-weight: bold; }
+    tspan {
+      font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+      white-space: pre;
+      line-height: 18px;
+    }
+  </style>
+
+  <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+  <text xml:space="preserve" class="container fg">
+    <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[</tspan><tspan class="fg-ansi256-009 bold"><a href="https://doc.rust-lang.org/error_codes/E0308.html">E0308</a></tspan><tspan class="fg-ansi256-009 bold">]</tspan><tspan class="bold">: mismatched types</tspan>
+</tspan>
+    <tspan x="10px" y="46px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/terminal_urls.rs:3:9</tspan>
+</tspan>
+    <tspan x="10px" y="64px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>     let () = 4;</tspan>
+</tspan>
+    <tspan x="10px" y="100px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-009 bold">^^</tspan><tspan>   </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">this expression has type `{integer}`</tspan>
+</tspan>
+    <tspan x="10px" y="118px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-009 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="136px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-009 bold">expected integer, found `()`</tspan>
+</tspan>
+    <tspan x="10px" y="154px">
+</tspan>
+    <tspan x="10px" y="172px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 1 previous error</tspan>
+</tspan>
+    <tspan x="10px" y="190px">
+</tspan>
+    <tspan x="10px" y="208px"><tspan class="bold">For more information about this error, try `rustc --explain E0308`.</tspan>
+</tspan>
+    <tspan x="10px" y="226px">
+</tspan>
+  </text>
+
+</svg>
diff --git a/tests/ui/diagnostic-flags/terminal_urls.windows.svg b/tests/ui/diagnostic-flags/terminal_urls.windows.svg
new file mode 100644
index 00000000000..e7b46638399
--- /dev/null
+++ b/tests/ui/diagnostic-flags/terminal_urls.windows.svg
@@ -0,0 +1,49 @@
+<svg width="740px" height="236px" xmlns="http://www.w3.org/2000/svg">
+  <style>
+    .fg { fill: #AAAAAA }
+    .bg { fill: #000000 }
+    .fg-ansi256-009 { fill: #FF5555 }
+    .fg-ansi256-014 { fill: #55FFFF }
+    .fg-ansi256-015 { fill: #FFFFFF }
+    .container {
+      padding: 0 10px;
+      line-height: 18px;
+    }
+    .bold { font-weight: bold; }
+    tspan {
+      font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+      white-space: pre;
+      line-height: 18px;
+    }
+  </style>
+
+  <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+  <text xml:space="preserve" class="container fg">
+    <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[</tspan><tspan class="fg-ansi256-009 bold"><a href="https://doc.rust-lang.org/error_codes/E0308.html">E0308</a></tspan><tspan class="fg-ansi256-009 bold">]</tspan><tspan class="fg-ansi256-015 bold">: mismatched types</tspan>
+</tspan>
+    <tspan x="10px" y="46px"><tspan>  </tspan><tspan class="fg-ansi256-014 bold">--&gt; </tspan><tspan>$DIR/terminal_urls.rs:3:9</tspan>
+</tspan>
+    <tspan x="10px" y="64px"><tspan>   </tspan><tspan class="fg-ansi256-014 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="82px"><tspan class="fg-ansi256-014 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-014 bold">|</tspan><tspan>     let () = 4;</tspan>
+</tspan>
+    <tspan x="10px" y="100px"><tspan>   </tspan><tspan class="fg-ansi256-014 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-009 bold">^^</tspan><tspan>   </tspan><tspan class="fg-ansi256-014 bold">-</tspan><tspan> </tspan><tspan class="fg-ansi256-014 bold">this expression has type `{integer}`</tspan>
+</tspan>
+    <tspan x="10px" y="118px"><tspan>   </tspan><tspan class="fg-ansi256-014 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-009 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="136px"><tspan>   </tspan><tspan class="fg-ansi256-014 bold">|</tspan><tspan>         </tspan><tspan class="fg-ansi256-009 bold">expected integer, found `()`</tspan>
+</tspan>
+    <tspan x="10px" y="154px">
+</tspan>
+    <tspan x="10px" y="172px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="fg-ansi256-015 bold">: aborting due to 1 previous error</tspan>
+</tspan>
+    <tspan x="10px" y="190px">
+</tspan>
+    <tspan x="10px" y="208px"><tspan class="fg-ansi256-015 bold">For more information about this error, try `rustc --explain E0308`.</tspan>
+</tspan>
+    <tspan x="10px" y="226px">
+</tspan>
+  </text>
+
+</svg>
diff --git a/tests/ui/error-emitter/E0308-clarification.svg b/tests/ui/error-emitter/E0308-clarification.svg
index 9432e3a4ee9..03ee973882d 100644
--- a/tests/ui/error-emitter/E0308-clarification.svg
+++ b/tests/ui/error-emitter/E0308-clarification.svg
@@ -1,7 +1,7 @@
 <svg width="740px" height="668px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-012 { fill: #5555FF }
     .fg-magenta { fill: #AA00AA }
diff --git a/tests/ui/error-emitter/highlighting.svg b/tests/ui/error-emitter/highlighting.svg
index 19818ab6146..d414f042f0a 100644
--- a/tests/ui/error-emitter/highlighting.svg
+++ b/tests/ui/error-emitter/highlighting.svg
@@ -1,7 +1,7 @@
 <svg width="785px" height="434px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-012 { fill: #5555FF }
diff --git a/tests/ui/error-emitter/highlighting.windows.svg b/tests/ui/error-emitter/highlighting.windows.svg
index f891bc1d2a6..92f9055cd1d 100644
--- a/tests/ui/error-emitter/highlighting.windows.svg
+++ b/tests/ui/error-emitter/highlighting.windows.svg
@@ -1,7 +1,7 @@
 <svg width="785px" height="434px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-014 { fill: #55FFFF }
diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.svg
index dd84234236d..5ffdc5a53fa 100644
--- a/tests/ui/error-emitter/multiline-multipart-suggestion.svg
+++ b/tests/ui/error-emitter/multiline-multipart-suggestion.svg
@@ -1,7 +1,7 @@
 <svg width="1306px" height="866px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-012 { fill: #5555FF }
diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg
index 144e57165da..37dc37e3e04 100644
--- a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg
+++ b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg
@@ -1,7 +1,7 @@
 <svg width="1306px" height="866px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-014 { fill: #55FFFF }
diff --git a/tests/ui/error-emitter/multiline-removal-suggestion.svg b/tests/ui/error-emitter/multiline-removal-suggestion.svg
index 7a88ac55b23..a774d558b58 100644
--- a/tests/ui/error-emitter/multiline-removal-suggestion.svg
+++ b/tests/ui/error-emitter/multiline-removal-suggestion.svg
@@ -1,7 +1,7 @@
-<svg width="2238px" height="3890px" xmlns="http://www.w3.org/2000/svg">
+<svg width="2288px" height="3890px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-012 { fill: #5555FF }
diff --git a/tests/ui/error-emitter/unicode-output.svg b/tests/ui/error-emitter/unicode-output.svg
index b253fff643b..bda4d1a2f28 100644
--- a/tests/ui/error-emitter/unicode-output.svg
+++ b/tests/ui/error-emitter/unicode-output.svg
@@ -1,7 +1,7 @@
 <svg width="785px" height="434px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-012 { fill: #5555FF }
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index f391cf92fb6..a1a78df8d53 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -8,7 +8,7 @@
 
 
 #![macro_export]
-//~^ ERROR: `macro_export` attribute cannot be used at crate level
+//~^ ERROR:  `#[macro_export]` attribute cannot be used on crates
 #![rustc_main]
 //~^ ERROR: `rustc_main` attribute cannot be used at crate level
 //~| ERROR: use of an internal attribute [E0658]
@@ -32,7 +32,6 @@
 mod inline {
     //~^ NOTE the inner attribute doesn't annotate this module
     //~| NOTE the inner attribute doesn't annotate this module
-    //~| NOTE the inner attribute doesn't annotate this module
 
     mod inner { #![inline] }
     //~^ ERROR attribute cannot be used on
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 3b010c3e312..4f4edeef420 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -8,6 +8,14 @@ LL | #![rustc_main]
    = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
    = note: the `#[rustc_main]` attribute is used internally to specify test entry point function
 
+error: `#[macro_export]` attribute cannot be used on crates
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:10:1
+   |
+LL | #![macro_export]
+   | ^^^^^^^^^^^^^^^^
+   |
+   = help: `#[macro_export]` can only be applied to macro defs
+
 error: `#[path]` attribute cannot be used on crates
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
    |
@@ -49,7 +57,7 @@ LL | #[inline]
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:37:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:17
    |
 LL |     mod inner { #![inline] }
    |                 ^^^^^^^^^^
@@ -57,7 +65,7 @@ LL |     mod inner { #![inline] }
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:45:5
    |
 LL |     #[inline] struct S;
    |     ^^^^^^^^^
@@ -65,7 +73,7 @@ LL |     #[inline] struct S;
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:49:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:48:5
    |
 LL |     #[inline] type T = S;
    |     ^^^^^^^^^
@@ -73,7 +81,7 @@ LL |     #[inline] type T = S;
    = help: `#[inline]` can only be applied to functions
 
 error: `#[inline]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:51:5
    |
 LL |     #[inline] impl S { }
    |     ^^^^^^^^^
@@ -81,7 +89,7 @@ LL |     #[inline] impl S { }
    = help: `#[inline]` can only be applied to functions
 
 error: `#[export_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:81:1
    |
 LL | #[export_name = "2200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -89,7 +97,7 @@ LL | #[export_name = "2200"]
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:85:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:17
    |
 LL |     mod inner { #![export_name="2200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^
@@ -97,7 +105,7 @@ LL |     mod inner { #![export_name="2200"] }
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:90:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:5
    |
 LL |     #[export_name = "2200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -105,7 +113,7 @@ LL |     #[export_name = "2200"] struct S;
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:93:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:92:5
    |
 LL |     #[export_name = "2200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -113,7 +121,7 @@ LL |     #[export_name = "2200"] type T = S;
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:95:5
    |
 LL |     #[export_name = "2200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -121,7 +129,7 @@ LL |     #[export_name = "2200"] impl S { }
    = help: `#[export_name]` can be applied to functions and statics
 
 error: `#[export_name]` attribute cannot be used on required trait methods
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:99:9
    |
 LL |         #[export_name = "2200"] fn foo();
    |         ^^^^^^^^^^^^^^^^^^^^^^^
@@ -129,7 +137,7 @@ LL |         #[export_name = "2200"] fn foo();
    = help: `#[export_name]` can be applied to statics, functions, inherent methods, provided trait methods, and trait methods in impl blocks
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:55:1
    |
 LL |   #[no_link]
    |   ^^^^^^^^^^
@@ -143,7 +151,7 @@ LL | | }
    | |_- not an `extern crate` item
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:107:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:8
    |
 LL |   #[repr(C)]
    |          ^
@@ -156,7 +164,7 @@ LL | | }
    | |_- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:130:8
    |
 LL |   #[repr(Rust)]
    |          ^^^^
@@ -174,21 +182,6 @@ error: attribute should be applied to an `extern crate` item
 LL | #![no_link]
    | ^^^^^^^^^^^ not an `extern crate` item
 
-error: `macro_export` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:10:1
-   |
-LL | #![macro_export]
-   | ^^^^^^^^^^^^^^^^
-...
-LL | mod inline {
-   |     ------ the inner attribute doesn't annotate this module
-   |
-help: perhaps you meant to use an outer attribute
-   |
-LL - #![macro_export]
-LL + #[macro_export]
-   |
-
 error: `rustc_main` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1
    |
@@ -220,85 +213,85 @@ LL + #[repr()]
    |
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:61:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:17
    |
 LL |     mod inner { #![no_link] }
    |     ------------^^^^^^^^^^^-- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:64:5
    |
 LL |     #[no_link] fn f() { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:69:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:5
    |
 LL |     #[no_link] struct S;
    |     ^^^^^^^^^^ --------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:73:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5
    |
 LL |     #[no_link]type T = S;
    |     ^^^^^^^^^^----------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:77:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5
    |
 LL |     #[no_link] impl S { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:111:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:25
    |
 LL |     mod inner { #![repr(C)] }
    |     --------------------^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:114:12
    |
 LL |     #[repr(C)] fn f() { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:121:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:12
    |
 LL |     #[repr(C)] type T = S;
    |            ^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:124:12
    |
 LL |     #[repr(C)] impl S { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:135:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:25
    |
 LL |     mod inner { #![repr(Rust)] }
    |     --------------------^^^^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:138:12
    |
 LL |     #[repr(Rust)] fn f() { }
    |            ^^^^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:145:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:144:12
    |
 LL |     #[repr(Rust)] type T = S;
    |            ^^^^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:148:12
    |
 LL |     #[repr(Rust)] impl S { }
    |            ^^^^   ---------- not a struct, enum, or union
 
 error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:39:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
@@ -313,7 +306,7 @@ Some errors have detailed explanations: E0517, E0658.
 For more information about an error, try `rustc --explain E0517`.
 Future incompatibility report: Future breakage diagnostic:
 error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:39:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index 546aa4052d3..aa5aab41e72 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -214,22 +214,40 @@ mod macro_use {
 }
 
 #[macro_export]
-//~^ WARN `#[macro_export]` only has an effect on macro definitions
+//~^ WARN `#[macro_export]` attribute cannot be used on modules [unused_attributes]
+//~| WARN previously accepted
+//~| HELP can only be applied to
+//~| HELP remove the attribute
 mod macro_export {
     mod inner { #![macro_export] }
-    //~^ WARN `#[macro_export]` only has an effect on macro definitions
+    //~^ WARN `#[macro_export]` attribute cannot be used on modules
+    //~| WARN previously accepted
+    //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[macro_export] fn f() { }
-    //~^ WARN `#[macro_export]` only has an effect on macro definitions
+    //~^ WARN `#[macro_export]` attribute cannot be used on function
+    //~| WARN previously accepted
+    //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[macro_export] struct S;
-    //~^ WARN `#[macro_export]` only has an effect on macro definitions
+    //~^ WARN `#[macro_export]` attribute cannot be used on structs
+    //~| WARN previously accepted
+    //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[macro_export] type T = S;
-    //~^ WARN `#[macro_export]` only has an effect on macro definitions
+    //~^ WARN `#[macro_export]` attribute cannot be used on type aliases
+    //~| WARN previously accepted
+    //~| HELP can only be applied to
+    //~| HELP remove the attribute
 
     #[macro_export] impl S { }
-    //~^ WARN `#[macro_export]` only has an effect on macro definitions
+    //~^ WARN  `#[macro_export]` attribute cannot be used on inherent impl blocks
+    //~| WARN previously accepted
+    //~| HELP can only be applied to
+    //~| HELP remove the attribute
 }
 
 // At time of unit test authorship, if compiling without `--test` then
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 3c835be5cff..5e2029c4516 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
@@ -1,5 +1,5 @@
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:529:17
    |
 LL |     mod inner { #![macro_escape] }
    |                 ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     mod inner { #![macro_escape] }
    = help: try an outer attribute: `#[macro_use]`
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:1
    |
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
@@ -186,31 +186,24 @@ warning: unknown lint: `x5100`
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
-warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1
+warning: crate-level attribute should be an inner attribute
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:1
    |
-LL | #[macro_export]
-   | ^^^^^^^^^^^^^^^
+LL | #[reexport_test_harness_main = "2900"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9
    |
 LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
-
-warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:1
-   |
-LL | #[reexport_test_harness_main = "2900"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
 help: add a `!`
    |
 LL | #![reexport_test_harness_main = "2900"]
    |  +
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:1
    |
 LL |   #[link(name = "x")]
    |   ^^^^^^^^^^^^^^^^^^^
@@ -226,7 +219,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:1
    |
 LL | #[windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -237,7 +230,7 @@ LL | #![windows_subsystem = "windows"]
    |  +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -248,7 +241,7 @@ LL | #![crate_type = "0800"]
    |  +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:845:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:863:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
@@ -259,7 +252,7 @@ LL | #![feature(x0600)]
    |  +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:870:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:888:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
@@ -270,7 +263,7 @@ LL | #![no_main]
    |  +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:894:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:912:1
    |
 LL | #[no_builtins]
    | ^^^^^^^^^^^^^^
@@ -296,44 +289,14 @@ LL | #![feature(rust1)]
    |
    = note: `#[warn(stable_features)]` on by default
 
-warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:17
-   |
-LL |     mod inner { #![macro_export] }
-   |                 ^^^^^^^^^^^^^^^^
-
-warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:222:5
-   |
-LL |     #[macro_export] fn f() { }
-   |     ^^^^^^^^^^^^^^^
-
-warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:225:5
-   |
-LL |     #[macro_export] struct S;
-   |     ^^^^^^^^^^^^^^^
-
-warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:5
-   |
-LL |     #[macro_export] type T = S;
-   |     ^^^^^^^^^^^^^^^
-
-warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5
-   |
-LL |     #[macro_export] impl S { }
-   |     ^^^^^^^^^^^^^^^
-
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:17
    |
 LL |     mod inner { #![reexport_test_harness_main="2900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:490:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5
    |
 LL |     #[reexport_test_harness_main = "2900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -344,7 +307,7 @@ LL |     #![reexport_test_harness_main = "2900"] fn f() { }
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5
    |
 LL |     #[reexport_test_harness_main = "2900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -355,7 +318,7 @@ LL |     #![reexport_test_harness_main = "2900"] struct S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:498:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:5
    |
 LL |     #[reexport_test_harness_main = "2900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -366,7 +329,7 @@ LL |     #![reexport_test_harness_main = "2900"] type T = S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:5
    |
 LL |     #[reexport_test_harness_main = "2900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -377,7 +340,7 @@ LL |     #![reexport_test_harness_main = "2900"] impl S { }
    |      +
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:719:17
    |
 LL |     mod inner { #![link(name = "x")] }
    |     ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block
@@ -385,7 +348,7 @@ LL |     mod inner { #![link(name = "x")] }
    = 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 an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5
    |
 LL |     #[link(name = "x")] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
@@ -393,7 +356,7 @@ LL |     #[link(name = "x")] fn f() { }
    = 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 an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5
    |
 LL |     #[link(name = "x")] struct S;
    |     ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block
@@ -401,7 +364,7 @@ LL |     #[link(name = "x")] struct S;
    = 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 an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5
    |
 LL |     #[link(name = "x")] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block
@@ -409,7 +372,7 @@ LL |     #[link(name = "x")] type T = S;
    = 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 an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:5
    |
 LL |     #[link(name = "x")] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block
@@ -417,7 +380,7 @@ LL |     #[link(name = "x")] impl S { }
    = 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 an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:5
    |
 LL |     #[link(name = "x")] extern "Rust" {}
    |     ^^^^^^^^^^^^^^^^^^^
@@ -425,13 +388,13 @@ LL |     #[link(name = "x")] extern "Rust" {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:17
    |
 LL |     mod inner { #![windows_subsystem="windows"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5
    |
 LL |     #[windows_subsystem = "windows"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -442,7 +405,7 @@ LL |     #![windows_subsystem = "windows"] fn f() { }
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:800:5
    |
 LL |     #[windows_subsystem = "windows"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -453,7 +416,7 @@ LL |     #![windows_subsystem = "windows"] struct S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:5
    |
 LL |     #[windows_subsystem = "windows"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -464,7 +427,7 @@ LL |     #![windows_subsystem = "windows"] type T = S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:5
    |
 LL |     #[windows_subsystem = "windows"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -475,13 +438,13 @@ LL |     #![windows_subsystem = "windows"] impl S { }
    |      +
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:825:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:828:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -492,7 +455,7 @@ LL |     #![crate_type = "0800"] fn f() { }
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:850:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -503,7 +466,7 @@ LL |     #![crate_type = "0800"] struct S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:854:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -514,7 +477,7 @@ LL |     #![crate_type = "0800"] type T = S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:858:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -525,13 +488,13 @@ LL |     #![crate_type = "0800"] impl S { }
    |      +
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:849:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:852:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:870:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
@@ -542,7 +505,7 @@ LL |     #![feature(x0600)] fn f() { }
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:874:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
@@ -553,7 +516,7 @@ LL |     #![feature(x0600)] struct S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:878:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
@@ -564,7 +527,7 @@ LL |     #![feature(x0600)] type T = S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:882:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
@@ -575,13 +538,13 @@ LL |     #![feature(x0600)] impl S { }
    |      +
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:874:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:877:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:895:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
@@ -592,7 +555,7 @@ LL |     #![no_main] fn f() { }
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:899:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
@@ -603,7 +566,7 @@ LL |     #![no_main] struct S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:903:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
@@ -614,7 +577,7 @@ LL |     #![no_main] type T = S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:907:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
@@ -625,13 +588,13 @@ LL |     #![no_main] impl S { }
    |      +
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:898:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:916:17
    |
 LL |     mod inner { #![no_builtins] }
    |                 ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:901:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:919:5
    |
 LL |     #[no_builtins] fn f() { }
    |     ^^^^^^^^^^^^^^
@@ -642,7 +605,7 @@ LL |     #![no_builtins] fn f() { }
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:905:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:923:5
    |
 LL |     #[no_builtins] struct S;
    |     ^^^^^^^^^^^^^^
@@ -653,7 +616,7 @@ LL |     #![no_builtins] struct S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:927:5
    |
 LL |     #[no_builtins] type T = S;
    |     ^^^^^^^^^^^^^^
@@ -664,7 +627,7 @@ LL |     #![no_builtins] type T = S;
    |      +
 
 warning: crate-level attribute should be an inner attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:913:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:931:5
    |
 LL |     #[no_builtins] impl S { }
    |     ^^^^^^^^^^^^^^
@@ -710,8 +673,62 @@ LL |     #[macro_use] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = help: `#[macro_use]` can be applied to modules, extern crates, and crates
 
+warning: `#[macro_export]` attribute cannot be used on modules
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1
+   |
+LL | #[macro_export]
+   | ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[macro_export]` can only be applied to macro defs
+
+warning: `#[macro_export]` attribute cannot be used on modules
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:222:17
+   |
+LL |     mod inner { #![macro_export] }
+   |                 ^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[macro_export]` can only be applied to macro defs
+
+warning: `#[macro_export]` attribute cannot be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:5
+   |
+LL |     #[macro_export] fn f() { }
+   |     ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[macro_export]` can only be applied to macro defs
+
+warning: `#[macro_export]` attribute cannot be used on structs
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:5
+   |
+LL |     #[macro_export] struct S;
+   |     ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[macro_export]` can only be applied to macro defs
+
+warning: `#[macro_export]` attribute cannot be used on type aliases
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:5
+   |
+LL |     #[macro_export] type T = S;
+   |     ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[macro_export]` can only be applied to macro defs
+
+warning: `#[macro_export]` attribute cannot be used on inherent impl blocks
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5
+   |
+LL |     #[macro_export] impl S { }
+   |     ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = help: `#[macro_export]` can only be applied to macro defs
+
 warning: `#[path]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5
    |
 LL |     #[path = "3800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^
@@ -720,7 +737,7 @@ LL |     #[path = "3800"] fn f() { }
    = help: `#[path]` can only be applied to modules
 
 warning: `#[path]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:277:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:295:5
    |
 LL |     #[path = "3800"]  struct S;
    |     ^^^^^^^^^^^^^^^^
@@ -729,7 +746,7 @@ LL |     #[path = "3800"]  struct S;
    = help: `#[path]` can only be applied to modules
 
 warning: `#[path]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:301:5
    |
 LL |     #[path = "3800"] type T = S;
    |     ^^^^^^^^^^^^^^^^
@@ -738,7 +755,7 @@ LL |     #[path = "3800"] type T = S;
    = help: `#[path]` can only be applied to modules
 
 warning: `#[path]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:307:5
    |
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
@@ -747,7 +764,7 @@ LL |     #[path = "3800"] impl S { }
    = help: `#[path]` can only be applied to modules
 
 warning: `#[automatically_derived]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:296:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -756,7 +773,7 @@ LL | #[automatically_derived]
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:302:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:320:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -765,7 +782,7 @@ LL |     mod inner { #![automatically_derived] }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:308:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -774,7 +791,7 @@ LL |     #[automatically_derived] fn f() { }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -783,7 +800,7 @@ LL |     #[automatically_derived] struct S;
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:320:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5
    |
 LL |     #[automatically_derived] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -792,7 +809,7 @@ LL |     #[automatically_derived] type T = S;
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on traits
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5
    |
 LL |     #[automatically_derived] trait W { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -801,7 +818,7 @@ LL |     #[automatically_derived] trait W { }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[automatically_derived]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5
    |
 LL |     #[automatically_derived] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -810,7 +827,7 @@ LL |     #[automatically_derived] impl S { }
    = help: `#[automatically_derived]` can only be applied to trait impl blocks
 
 warning: `#[no_mangle]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:359:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^
@@ -819,7 +836,7 @@ LL | #[no_mangle]
    = help: `#[no_mangle]` can be applied to functions and statics
 
 warning: `#[no_mangle]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:17
    |
 LL |     mod inner { #![no_mangle] }
    |                 ^^^^^^^^^^^^^
@@ -828,7 +845,7 @@ LL |     mod inner { #![no_mangle] }
    = help: `#[no_mangle]` can be applied to functions and statics
 
 warning: `#[no_mangle]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5
    |
 LL |     #[no_mangle] struct S;
    |     ^^^^^^^^^^^^
@@ -837,7 +854,7 @@ LL |     #[no_mangle] struct S;
    = help: `#[no_mangle]` can be applied to functions and statics
 
 warning: `#[no_mangle]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5
    |
 LL |     #[no_mangle] type T = S;
    |     ^^^^^^^^^^^^
@@ -846,7 +863,7 @@ LL |     #[no_mangle] type T = S;
    = help: `#[no_mangle]` can be applied to functions and statics
 
 warning: `#[no_mangle]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5
    |
 LL |     #[no_mangle] impl S { }
    |     ^^^^^^^^^^^^
@@ -855,7 +872,7 @@ LL |     #[no_mangle] impl S { }
    = help: `#[no_mangle]` can be applied to functions and statics
 
 warning: `#[no_mangle]` attribute cannot be used on required trait methods
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:9
    |
 LL |         #[no_mangle] fn foo();
    |         ^^^^^^^^^^^^
@@ -864,7 +881,7 @@ LL |         #[no_mangle] fn foo();
    = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, and trait methods in impl blocks
 
 warning: `#[no_mangle]` attribute cannot be used on provided trait methods
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:9
    |
 LL |         #[no_mangle] fn bar() {}
    |         ^^^^^^^^^^^^
@@ -873,7 +890,7 @@ LL |         #[no_mangle] fn bar() {}
    = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, and trait methods in impl blocks
 
 warning: `#[should_panic]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
@@ -882,7 +899,7 @@ LL | #[should_panic]
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:17
    |
 LL |     mod inner { #![should_panic] }
    |                 ^^^^^^^^^^^^^^^^
@@ -891,7 +908,7 @@ LL |     mod inner { #![should_panic] }
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5
    |
 LL |     #[should_panic] struct S;
    |     ^^^^^^^^^^^^^^^
@@ -900,7 +917,7 @@ LL |     #[should_panic] struct S;
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5
    |
 LL |     #[should_panic] type T = S;
    |     ^^^^^^^^^^^^^^^
@@ -909,7 +926,7 @@ LL |     #[should_panic] type T = S;
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[should_panic]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5
    |
 LL |     #[should_panic] impl S { }
    |     ^^^^^^^^^^^^^^^
@@ -918,7 +935,7 @@ LL |     #[should_panic] impl S { }
    = help: `#[should_panic]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
@@ -927,7 +944,7 @@ LL | #[ignore]
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:17
    |
 LL |     mod inner { #![ignore] }
    |                 ^^^^^^^^^^
@@ -936,7 +953,7 @@ LL |     mod inner { #![ignore] }
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:435:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:5
    |
 LL |     #[ignore] struct S;
    |     ^^^^^^^^^
@@ -945,7 +962,7 @@ LL |     #[ignore] struct S;
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:441:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:5
    |
 LL |     #[ignore] type T = S;
    |     ^^^^^^^^^
@@ -954,7 +971,7 @@ LL |     #[ignore] type T = S;
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[ignore]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5
    |
 LL |     #[ignore] impl S { }
    |     ^^^^^^^^^
@@ -963,7 +980,7 @@ LL |     #[ignore] impl S { }
    = help: `#[ignore]` can only be applied to functions
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5
    |
 LL |     #[no_implicit_prelude] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -972,7 +989,7 @@ LL |     #[no_implicit_prelude] fn f() { }
    = help: `#[no_implicit_prelude]` can be applied to modules and crates
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5
    |
 LL |     #[no_implicit_prelude] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -981,7 +998,7 @@ LL |     #[no_implicit_prelude] struct S;
    = help: `#[no_implicit_prelude]` can be applied to modules and crates
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5
    |
 LL |     #[no_implicit_prelude] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -990,7 +1007,7 @@ LL |     #[no_implicit_prelude] type T = S;
    = help: `#[no_implicit_prelude]` can be applied to modules and crates
 
 warning: `#[no_implicit_prelude]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:5
    |
 LL |     #[no_implicit_prelude] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -999,7 +1016,7 @@ LL |     #[no_implicit_prelude] impl S { }
    = help: `#[no_implicit_prelude]` can be applied to modules and crates
 
 warning: `#[macro_escape]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5
    |
 LL |     #[macro_escape] fn f() { }
    |     ^^^^^^^^^^^^^^^
@@ -1008,7 +1025,7 @@ LL |     #[macro_escape] fn f() { }
    = help: `#[macro_escape]` can be applied to modules, extern crates, and crates
 
 warning: `#[macro_escape]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:521:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:539:5
    |
 LL |     #[macro_escape] struct S;
    |     ^^^^^^^^^^^^^^^
@@ -1017,7 +1034,7 @@ LL |     #[macro_escape] struct S;
    = help: `#[macro_escape]` can be applied to modules, extern crates, and crates
 
 warning: `#[macro_escape]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:527:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:545:5
    |
 LL |     #[macro_escape] type T = S;
    |     ^^^^^^^^^^^^^^^
@@ -1026,7 +1043,7 @@ LL |     #[macro_escape] type T = S;
    = help: `#[macro_escape]` can be applied to modules, extern crates, and crates
 
 warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5
    |
 LL |     #[macro_escape] impl S { }
    |     ^^^^^^^^^^^^^^^
@@ -1035,13 +1052,13 @@ LL |     #[macro_escape] impl S { }
    = help: `#[macro_escape]` can be applied to modules, extern crates, and crates
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:558:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:560:1
    |
 LL | / mod no_std {
 LL | |
@@ -1051,61 +1068,61 @@ LL | | }
    | |_^
 
 warning: the `#![no_std]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:562:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:15
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:15
    |
 LL |     #[no_std] fn f() { }
    |               ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:15
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:15
    |
 LL |     #[no_std] struct S;
    |               ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:15
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:15
    |
 LL |     #[no_std] type T = S;
    |               ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:15
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:15
    |
 LL |     #[no_std] impl S { }
    |               ^^^^^^^^^^
 
 warning: `#[cold]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:599:1
    |
 LL | #[cold]
    | ^^^^^^^
@@ -1114,7 +1131,7 @@ LL | #[cold]
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:17
    |
 LL |     mod inner { #![cold] }
    |                 ^^^^^^^^
@@ -1123,7 +1140,7 @@ LL |     mod inner { #![cold] }
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:596:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5
    |
 LL |     #[cold] struct S;
    |     ^^^^^^^
@@ -1132,7 +1149,7 @@ LL |     #[cold] struct S;
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5
    |
 LL |     #[cold] type T = S;
    |     ^^^^^^^
@@ -1141,7 +1158,7 @@ LL |     #[cold] type T = S;
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[cold]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:608:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5
    |
 LL |     #[cold] impl S { }
    |     ^^^^^^^
@@ -1150,7 +1167,7 @@ LL |     #[cold] impl S { }
    = help: `#[cold]` can only be applied to functions
 
 warning: `#[link_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:1
    |
 LL | #[link_name = "1900"]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -1159,7 +1176,7 @@ LL | #[link_name = "1900"]
    = help: `#[link_name]` can be applied to foreign functions and foreign statics
 
 warning: `#[link_name]` attribute cannot be used on foreign modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:621:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1168,7 +1185,7 @@ LL |     #[link_name = "1900"]
    = help: `#[link_name]` can be applied to foreign functions and foreign statics
 
 warning: `#[link_name]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:628:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:17
    |
 LL |     mod inner { #![link_name="1900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^
@@ -1177,7 +1194,7 @@ LL |     mod inner { #![link_name="1900"] }
    = help: `#[link_name]` can be applied to foreign functions and foreign statics
 
 warning: `#[link_name]` attribute cannot be used on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5
    |
 LL |     #[link_name = "1900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1186,7 +1203,7 @@ LL |     #[link_name = "1900"] fn f() { }
    = help: `#[link_name]` can be applied to foreign functions and foreign statics
 
 warning: `#[link_name]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:5
    |
 LL |     #[link_name = "1900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1195,7 +1212,7 @@ LL |     #[link_name = "1900"] struct S;
    = help: `#[link_name]` can be applied to foreign functions and foreign statics
 
 warning: `#[link_name]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5
    |
 LL |     #[link_name = "1900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1204,7 +1221,7 @@ LL |     #[link_name = "1900"] type T = S;
    = help: `#[link_name]` can be applied to foreign functions and foreign statics
 
 warning: `#[link_name]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:5
    |
 LL |     #[link_name = "1900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -1213,7 +1230,7 @@ LL |     #[link_name = "1900"] impl S { }
    = help: `#[link_name]` can be applied to foreign functions and foreign statics
 
 warning: `#[link_section]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:1
    |
 LL | #[link_section = "1800"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1222,7 +1239,7 @@ LL | #[link_section = "1800"]
    = help: `#[link_section]` can be applied to statics and functions
 
 warning: `#[link_section]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:17
    |
 LL |     mod inner { #![link_section="1800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
@@ -1231,7 +1248,7 @@ LL |     mod inner { #![link_section="1800"] }
    = help: `#[link_section]` can be applied to statics and functions
 
 warning: `#[link_section]` attribute cannot be used on structs
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:5
    |
 LL |     #[link_section = "1800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1240,7 +1257,7 @@ LL |     #[link_section = "1800"] struct S;
    = help: `#[link_section]` can be applied to statics and functions
 
 warning: `#[link_section]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5
    |
 LL |     #[link_section = "1800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1249,7 +1266,7 @@ LL |     #[link_section = "1800"] type T = S;
    = help: `#[link_section]` can be applied to statics and functions
 
 warning: `#[link_section]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5
    |
 LL |     #[link_section = "1800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1258,7 +1275,7 @@ LL |     #[link_section = "1800"] impl S { }
    = help: `#[link_section]` can be applied to statics and functions
 
 warning: `#[must_use]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
@@ -1267,7 +1284,7 @@ LL | #[must_use]
    = help: `#[must_use]` can be applied to functions, data types, unions, and traits
 
 warning: `#[must_use]` attribute cannot be used on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:17
    |
 LL |     mod inner { #![must_use] }
    |                 ^^^^^^^^^^^^
@@ -1276,7 +1293,7 @@ LL |     mod inner { #![must_use] }
    = help: `#[must_use]` can be applied to functions, data types, unions, and traits
 
 warning: `#[must_use]` attribute cannot be used on type aliases
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:778:5
    |
 LL |     #[must_use] type T = S;
    |     ^^^^^^^^^^^
@@ -1285,7 +1302,7 @@ LL |     #[must_use] type T = S;
    = help: `#[must_use]` can be applied to functions, data types, unions, and traits
 
 warning: `#[must_use]` attribute cannot be used on inherent impl blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:5
    |
 LL |     #[must_use] impl S { }
    |     ^^^^^^^^^^^
@@ -1294,13 +1311,13 @@ LL |     #[must_use] impl S { }
    = help: `#[must_use]` can be applied to functions, data types, unions, and traits
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:1
    |
 LL | / mod crate_name {
 LL | |
@@ -1310,67 +1327,67 @@ LL | | }
    | |_^
 
 warning: the `#![crate_name]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:804:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:28
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |                            ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:28
    |
 LL |     #[crate_name = "0900"] struct S;
    |                            ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:28
    |
 LL |     #[crate_name = "0900"] type T = S;
    |                            ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:28
    |
 LL |     #[crate_name = "0900"] impl S { }
    |                            ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:938:1
    |
 LL | / mod recursion_limit {
 LL | |
@@ -1380,67 +1397,67 @@ LL | | }
    | |_^
 
 warning: the `#![recursion_limit]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:922:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:943:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:943:31
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |                               ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:947:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:947:31
    |
 LL |     #[recursion_limit="0200"] struct S;
    |                               ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:951:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:951:31
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |                               ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:955:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:31
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:955:31
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |                               ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:960:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:962:1
    |
 LL | / mod type_length_limit {
 LL | |
@@ -1450,55 +1467,55 @@ LL | | }
    | |_^
 
 warning: the `#![type_length_limit]` attribute can only be used at the crate root
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:946:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:967:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:967:33
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |                                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:971:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this struct
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:971:33
    |
 LL |     #[type_length_limit="0100"] struct S;
    |                                 ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:975:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:975:33
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |                                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:979:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: This attribute does not have an `!`, which means it is applied to this implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:33
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:979:33
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |                                 ^^^^^^^^^^
diff --git a/tests/ui/frontmatter/unclosed-6.rs b/tests/ui/frontmatter/unclosed-6.rs
new file mode 100644
index 00000000000..ea8d4702f63
--- /dev/null
+++ b/tests/ui/frontmatter/unclosed-6.rs
@@ -0,0 +1,12 @@
+---
+//~^ ERROR unclosed frontmatter
+🦀---
+ ---
+
+// This test checks the location of the --- recovered by the parser is not
+// incorrectly tracked during the less fortunate recovery case and multiple
+// candidates are found, as seen with #146847
+
+#![feature(frontmatter)]
+
+fn main() {}
diff --git a/tests/ui/frontmatter/unclosed-6.stderr b/tests/ui/frontmatter/unclosed-6.stderr
new file mode 100644
index 00000000000..01a13e87268
--- /dev/null
+++ b/tests/ui/frontmatter/unclosed-6.stderr
@@ -0,0 +1,19 @@
+error: unclosed frontmatter
+  --> $DIR/unclosed-6.rs:1:1
+   |
+LL | / ---
+LL | |
+LL | | 🦀---
+LL | |  ---
+...  |
+LL | |
+   | |_^
+   |
+note: frontmatter opening here was not closed
+  --> $DIR/unclosed-6.rs:1:1
+   |
+LL | ---
+   | ^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs
new file mode 100644
index 00000000000..dfdb816652c
--- /dev/null
+++ b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Zdeduplicate-diagnostics=yes
+
+// Regression test for #146467.
+trait Trait { type Assoc; }
+
+impl Trait for fn(&()) { type Assoc = (); }
+
+fn f(_: for<'a> fn(<fn(&'a ()) as Trait>::Assoc)) {}
+//~^ ERROR implementation of `Trait` is not general enough
+//~| ERROR higher-ranked subtype error
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr
new file mode 100644
index 00000000000..c75a063e45f
--- /dev/null
+++ b/tests/ui/higher-ranked/do-not-blame-outlives-static-ice.stderr
@@ -0,0 +1,17 @@
+error: implementation of `Trait` is not general enough
+  --> $DIR/do-not-blame-outlives-static-ice.rs:8:9
+   |
+LL | fn f(_: for<'a> fn(<fn(&'a ()) as Trait>::Assoc)) {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `for<'a> fn(&'a ())` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `for<'a> fn(&'a ())`
+
+error: higher-ranked subtype error
+  --> $DIR/do-not-blame-outlives-static-ice.rs:8:1
+   |
+LL | fn f(_: for<'a> fn(<fn(&'a ()) as Trait>::Assoc)) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
index 73acb072ac5..6077dbdc200 100644
--- a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
@@ -1,7 +1,7 @@
-<svg width="1188px" height="398px" xmlns="http://www.w3.org/2000/svg">
+<svg width="1096px" height="398px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-012 { fill: #5555FF }
diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr
index 3de317d2af6..a78941f9e11 100644
--- a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr
+++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr
@@ -1,10 +1,10 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:22
+  --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:5
    |
 LL |     println!("{:?}", []);
-   |                      ^^ cannot infer type
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot infer type
    |
-   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/intrinsics/intrinsic-fmuladd.rs b/tests/ui/intrinsics/intrinsic-fmuladd.rs
index d03297884f7..ab4285590cb 100644
--- a/tests/ui/intrinsics/intrinsic-fmuladd.rs
+++ b/tests/ui/intrinsics/intrinsic-fmuladd.rs
@@ -11,7 +11,7 @@ macro_rules! assert_approx_eq {
 }
 
 fn main() {
-    unsafe {
+    {
         let nan: f32 = f32::NAN;
         let inf: f32 = f32::INFINITY;
         let neg_inf: f32 = f32::NEG_INFINITY;
@@ -25,7 +25,7 @@ fn main() {
         assert_eq!(fmuladdf32(8.9, inf, 3.2), inf);
         assert_eq!(fmuladdf32(-3.2, 2.4, neg_inf), neg_inf);
     }
-    unsafe {
+    {
         let nan: f64 = f64::NAN;
         let inf: f64 = f64::INFINITY;
         let neg_inf: f64 = f64::NEG_INFINITY;
diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr
index aea6f838e0d..1307a85c8b6 100644
--- a/tests/ui/intrinsics/reify-intrinsic.stderr
+++ b/tests/ui/intrinsics/reify-intrinsic.stderr
@@ -22,7 +22,7 @@ LL |         std::intrinsics::floorf32,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
    |
    = note: expected fn pointer `unsafe fn(_) -> _`
-                 found fn item `unsafe fn(_) -> _ {floorf32}`
+                 found fn item `fn(_) -> _ {floorf32}`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr
index dae08119dbc..277111a41f2 100644
--- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr
+++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGS.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected
+error: incorrect value `leaf` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected
 
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
index 13f79e94674..e1ade01d2fe 100644
--- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
+++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.BADFLAGSPC.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf` was expected
+error: incorrect value `pc` for unstable option `branch-protection` - a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set) was expected
 
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.rs b/tests/ui/invalid/invalid-debugger-visualizer-option.rs
index 0f1cf15a687..166962866dc 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-option.rs
+++ b/tests/ui/invalid/invalid-debugger-visualizer-option.rs
@@ -1,6 +1,6 @@
 //@ normalize-stderr: "foo.random:.*\(" -> "foo.random: $$FILE_NOT_FOUND_MSG ("
 //@ normalize-stderr: "os error \d+" -> "os error $$FILE_NOT_FOUND_CODE"
 
-#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR invalid argument
+#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR malformed `debugger_visualizer` attribute input
 #![debugger_visualizer(natvis_file = "../foo.random")] //~ ERROR
 fn main() {}
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-option.stderr b/tests/ui/invalid/invalid-debugger-visualizer-option.stderr
index 6fbb4d641e6..e877e39d8f1 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-option.stderr
+++ b/tests/ui/invalid/invalid-debugger-visualizer-option.stderr
@@ -1,18 +1,20 @@
-error: invalid argument
-  --> $DIR/invalid-debugger-visualizer-option.rs:4:24
-   |
-LL | #![debugger_visualizer(random_file = "../foo.random")]
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: expected: `natvis_file = "..."`
-   = note: OR
-   = note: expected: `gdb_script_file = "..."`
-
 error: couldn't read $DIR/../foo.random: $FILE_NOT_FOUND_MSG (os error $FILE_NOT_FOUND_CODE)
   --> $DIR/invalid-debugger-visualizer-option.rs:5:24
    |
 LL | #![debugger_visualizer(natvis_file = "../foo.random")]
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0539]: malformed `debugger_visualizer` attribute input
+  --> $DIR/invalid-debugger-visualizer-option.rs:4:1
+   |
+LL | #![debugger_visualizer(random_file = "../foo.random")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^^^^^^^
+   | |                      |
+   | |                      valid arguments are `natvis_file` or `gdb_script_file`
+   | help: must be of the form: `#![debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
+
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.rs b/tests/ui/invalid/invalid-debugger-visualizer-target.rs
index 1efb9555c24..48b04153214 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-target.rs
+++ b/tests/ui/invalid/invalid-debugger-visualizer-target.rs
@@ -1,2 +1,3 @@
-#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module
+#[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
+//~^ ERROR `#[debugger_visualizer]` attribute cannot be used on functions
 fn main() {}
diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr
index 1df34532533..629af94c5ef 100644
--- a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr
+++ b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr
@@ -1,8 +1,10 @@
-error: attribute should be applied to a module
+error: `#[debugger_visualizer]` attribute cannot be used on functions
   --> $DIR/invalid-debugger-visualizer-target.rs:1:1
    |
 LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `#[debugger_visualizer]` can be applied to modules and crates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-27592.stderr b/tests/ui/issues/issue-27592.stderr
index c8649d82d74..f1de7b9e569 100644
--- a/tests/ui/issues/issue-27592.stderr
+++ b/tests/ui/issues/issue-27592.stderr
@@ -1,3 +1,9 @@
+error[E0515]: cannot return reference to temporary value
+  --> $DIR/issue-27592.rs:16:14
+   |
+LL |     write(|| format_args!("{}", String::from("Hello world")));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function
+
 error[E0515]: cannot return value referencing temporary value
   --> $DIR/issue-27592.rs:16:14
    |
@@ -7,12 +13,6 @@ LL |     write(|| format_args!("{}", String::from("Hello world")));
    |              |                  temporary value created here
    |              returns a value referencing data owned by the current function
 
-error[E0515]: cannot return reference to temporary value
-  --> $DIR/issue-27592.rs:16:14
-   |
-LL |     write(|| format_args!("{}", String::from("Hello world")));
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function
-
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs
index 6730865b6c7..525a2e39a91 100644
--- a/tests/ui/iterators/issue-58952-filter-type-length.rs
+++ b/tests/ui/iterators/issue-58952-filter-type-length.rs
@@ -2,7 +2,7 @@
 
 //! This snippet causes the type length to blowup exponentially,
 //! so check that we don't accidentally exceed the type length limit.
-// FIXME: Once the size of iterator adaptors is further reduced,
+// FIXME: Once the size of iterator adapters is further reduced,
 // increase the complexity of this test.
 use std::collections::VecDeque;
 
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
deleted file mode 100644
index 35d5d079c68..00000000000
--- a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-#![feature(lang_items, no_core)]
-#![no_core]
-#![no_main]
-
-#[lang = "pointee_sized"]
-pub trait PointeeSized {}
-
-#[lang = "meta_sized"]
-pub trait MetaSized: PointeeSized {}
-
-#[lang = "sized"]
-trait Sized: MetaSized { }
-
-struct S;
-
-#[no_mangle]
-extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
-    argc //~ ERROR requires `copy` lang_item
-}
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
deleted file mode 100644
index 7b9541f734f..00000000000
--- a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: requires `copy` lang_item
-  --> $DIR/missing-copy-lang-item-issue-19660.rs:18:5
-   |
-LL |     argc
-   |     ^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs
index bb537f855a4..7de786dff3b 100644
--- a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs
+++ b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.rs
@@ -1,4 +1,4 @@
-//@ edition:2024
+//@ reference: destructors.scope.lifetime-extension.exprs
 
 fn temp() -> String {
     String::from("Hello")
@@ -22,7 +22,7 @@ fn main() {
     let a = &temp();
     let b = Some(&temp());
     let c = Option::Some::<&String>(&temp());
-    use Option::Some as S;
+    use std::option::Option::Some as S;
     let d = S(&temp());
     let e = X(&temp());
     let f = Some(Ok::<_, ()>(std::borrow::Cow::Borrowed(if true {
@@ -31,6 +31,6 @@ fn main() {
         panic!()
     })));
     let some = Some; // Turn the ctor into a regular function.
-    let g = some(&temp()); //~ERROR temporary value dropped while borrowe
+    let g = some(&temp()); //~ERROR temporary value dropped while borrowed
     println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}");
 }
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr
index 3a3b450f3c5..fa2c9e59a41 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr
@@ -54,18 +54,6 @@ LL | #![no_builtins]
    | ^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:44:5
-   |
-LL |     #[macro_export]
-   |     ^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:43:5
-   |
-LL |     #[macro_export]
-   |     ^^^^^^^^^^^^^^^
-
-error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:41:1
    |
 LL | #[macro_use]
@@ -78,6 +66,18 @@ LL | #[macro_use]
    | ^^^^^^^^^^^^
 
 error: unused attribute
+  --> $DIR/unused-attr-duplicate.rs:44:5
+   |
+LL |     #[macro_export]
+   |     ^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/unused-attr-duplicate.rs:43:5
+   |
+LL |     #[macro_export]
+   |     ^^^^^^^^^^^^^^^
+
+error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:51:1
    |
 LL | #[path = "bar.rs"]
diff --git a/tests/ui/panic-runtime/auxiliary/needs-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-abort.rs
index 21f862e4b43..cba4907dbb6 100644
--- a/tests/ui/panic-runtime/auxiliary/needs-abort.rs
+++ b/tests/ui/panic-runtime/auxiliary/needs-abort.rs
@@ -1,5 +1,7 @@
 //@ compile-flags:-C panic=abort
 //@ no-prefer-dynamic
 
+#![feature(no_core)]
 #![crate_type = "rlib"]
 #![no_std]
+#![no_core]
diff --git a/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs
new file mode 100644
index 00000000000..4a41d16faa0
--- /dev/null
+++ b/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs
@@ -0,0 +1,7 @@
+//@ compile-flags:-C panic=immediate-abort -Zunstable-options
+//@ no-prefer-dynamic
+
+#![feature(no_core)]
+#![crate_type = "rlib"]
+#![no_std]
+#![no_core]
diff --git a/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs
new file mode 100644
index 00000000000..295876fec52
--- /dev/null
+++ b/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs
@@ -0,0 +1,18 @@
+//@ compile-flags:-C panic=unwind
+//@ no-prefer-dynamic
+//@ add-core-stubs
+
+#![crate_type = "rlib"]
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+
+extern "C-unwind" fn foo() {}
+
+#[inline]
+fn bar() {
+    let ptr: extern "C-unwind" fn() = foo;
+    ptr();
+}
diff --git a/tests/ui/panic-runtime/bad-panic-flag1.rs b/tests/ui/panic-runtime/bad-panic-flag1.rs
index 117935847cb..575e30f785c 100644
--- a/tests/ui/panic-runtime/bad-panic-flag1.rs
+++ b/tests/ui/panic-runtime/bad-panic-flag1.rs
@@ -2,4 +2,4 @@
 
 fn main() {}
 
-//~? ERROR incorrect value `foo` for codegen option `panic` - either `unwind` or `abort` was expected
+//~? ERROR incorrect value `foo` for codegen option `panic` - either `unwind`, `abort`, or `immediate-abort` was expected
diff --git a/tests/ui/panic-runtime/bad-panic-flag1.stderr b/tests/ui/panic-runtime/bad-panic-flag1.stderr
index 013373c6f93..c30598bba53 100644
--- a/tests/ui/panic-runtime/bad-panic-flag1.stderr
+++ b/tests/ui/panic-runtime/bad-panic-flag1.stderr
@@ -1,2 +1,2 @@
-error: incorrect value `foo` for codegen option `panic` - either `unwind` or `abort` was expected
+error: incorrect value `foo` for codegen option `panic` - either `unwind`, `abort`, or `immediate-abort` was expected
 
diff --git a/tests/ui/panic-runtime/bad-panic-flag2.rs b/tests/ui/panic-runtime/bad-panic-flag2.rs
index b5d0442a033..4e34da217d7 100644
--- a/tests/ui/panic-runtime/bad-panic-flag2.rs
+++ b/tests/ui/panic-runtime/bad-panic-flag2.rs
@@ -2,4 +2,4 @@
 
 fn main() {}
 
-//~? ERROR codegen option `panic` requires either `unwind` or `abort`
+//~? ERROR codegen option `panic` requires either `unwind`, `abort`, or `immediate-abort`
diff --git a/tests/ui/panic-runtime/bad-panic-flag2.stderr b/tests/ui/panic-runtime/bad-panic-flag2.stderr
index 6ab94ea704d..c8d12749c5d 100644
--- a/tests/ui/panic-runtime/bad-panic-flag2.stderr
+++ b/tests/ui/panic-runtime/bad-panic-flag2.stderr
@@ -1,2 +1,2 @@
-error: codegen option `panic` requires either `unwind` or `abort` (C panic=<value>)
+error: codegen option `panic` requires either `unwind`, `abort`, or `immediate-abort` (C panic=<value>)
 
diff --git a/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs b/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs
new file mode 100644
index 00000000000..94dc7c5671e
--- /dev/null
+++ b/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs
@@ -0,0 +1,15 @@
+//@ build-fail
+//@ aux-build:needs-unwind.rs
+//@ compile-flags:-C panic=immediate-abort -Zunstable-options
+//@ no-prefer-dynamic
+
+extern crate needs_unwind;
+
+// immediate-abort does not require any panic runtime, so trying to build a binary crate with
+// panic=immediate-abort and the precompiled sysroot will fail to link, because no panic runtime
+// provides the panic entrypoints used by sysroot crates.
+// This test ensures that we get a clean compile error instead of a linker error.
+
+fn main() {}
+
+//~? ERROR the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort`
diff --git a/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr b/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr
new file mode 100644
index 00000000000..bd6bdd8b667
--- /dev/null
+++ b/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr
@@ -0,0 +1,4 @@
+error: the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs b/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs
new file mode 100644
index 00000000000..78977c60be9
--- /dev/null
+++ b/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs
@@ -0,0 +1,21 @@
+//@ build-fail
+//@ aux-build:needs-abort.rs
+//@ compile-flags:-Cpanic=immediate-abort -Zunstable-options
+//@ no-prefer-dynamic
+//@ add-core-stubs
+//@ core-stubs-compile-flags: -Cpanic=immediate-abort -Zunstable-options
+
+#![feature(no_core)]
+#![no_std]
+#![no_main]
+#![no_core]
+
+extern crate minicore;
+extern crate needs_abort;
+
+#[no_mangle]
+extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
+    0
+}
+
+//~? ERROR the crate `needs_abort` was compiled with a panic strategy which is incompatible with `immediate-abort`
diff --git a/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr b/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr
new file mode 100644
index 00000000000..65a26b676b9
--- /dev/null
+++ b/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr
@@ -0,0 +1,4 @@
+error: the crate `needs_abort` was compiled with a panic strategy which is incompatible with `immediate-abort`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs b/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs
new file mode 100644
index 00000000000..1c5f597a3f9
--- /dev/null
+++ b/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs
@@ -0,0 +1,20 @@
+//@ build-fail
+//@ aux-build:needs-immediate-abort.rs
+//@ compile-flags:-C panic=abort
+//@ no-prefer-dynamic
+//@ add-core-stubs
+//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort
+
+#![feature(no_core)]
+#![no_std]
+#![no_main]
+#![no_core]
+
+extern crate minicore;
+extern crate needs_immediate_abort;
+
+extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 {
+    0
+}
+
+//~? ERROR the crate `need_immediate_abort_got_abort` was compiled with a panic strategy which is incompatible with `immediate-abort`
diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr b/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr
new file mode 100644
index 00000000000..8dcf120cb9f
--- /dev/null
+++ b/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr
@@ -0,0 +1,4 @@
+error: the crate `need_immediate_abort_got_abort` was compiled with a panic strategy which is incompatible with `immediate-abort`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs
new file mode 100644
index 00000000000..24d521230d4
--- /dev/null
+++ b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs
@@ -0,0 +1,20 @@
+//@ build-fail
+//@ needs-unwind
+//@ aux-build:needs-immediate-abort.rs
+//@ no-prefer-dynamic
+//@ add-core-stubs
+//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort
+
+#![feature(no_core)]
+#![no_std]
+#![no_main]
+#![no_core]
+
+extern crate minicore;
+extern crate needs_immediate_abort;
+
+extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 {
+    0
+}
+
+//~? ERROR the crate `need_immediate_abort_got_unwind` was compiled with a panic strategy which is incompatible with `immediate-abort`
diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr
new file mode 100644
index 00000000000..740fc80a77d
--- /dev/null
+++ b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr
@@ -0,0 +1,4 @@
+error: the crate `need_immediate_abort_got_unwind` was compiled with a panic strategy which is incompatible with `immediate-abort`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs
new file mode 100644
index 00000000000..5aec028a46c
--- /dev/null
+++ b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs
@@ -0,0 +1,21 @@
+//@ build-fail
+//@ aux-build:needs-unwind-immediate-abort.rs
+//@ compile-flags:-C panic=immediate-abort -Zunstable-options
+//@ no-prefer-dynamic
+//@ add-core-stubs
+//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort
+
+#![feature(no_core)]
+#![no_std]
+#![no_main]
+#![no_core]
+
+extern crate minicore;
+extern crate needs_unwind_immediate_abort;
+
+#[no_mangle]
+extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 {
+    0
+}
+
+//~? ERROR the crate `needs_unwind_immediate_abort` was compiled with a panic strategy which is incompatible with `immediate-abort`
diff --git a/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr
new file mode 100644
index 00000000000..8b3747d644f
--- /dev/null
+++ b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr
@@ -0,0 +1,4 @@
+error: the crate `needs_unwind_immediate_abort` was compiled with a panic strategy which is incompatible with `immediate-abort`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/proc-macro/panic-abort.rs b/tests/ui/proc-macro/panic-abort.rs
index 58e1d006433..adedba4ebca 100644
--- a/tests/ui/proc-macro/panic-abort.rs
+++ b/tests/ui/proc-macro/panic-abort.rs
@@ -2,4 +2,4 @@
 //@ force-host
 //@ check-pass
 
-//~? WARN building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+//~? WARN building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic
diff --git a/tests/ui/proc-macro/panic-abort.stderr b/tests/ui/proc-macro/panic-abort.stderr
index a6e18614f8f..3dd75768bc4 100644
--- a/tests/ui/proc-macro/panic-abort.stderr
+++ b/tests/ui/proc-macro/panic-abort.stderr
@@ -1,4 +1,4 @@
-warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+warning: building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic
 
 warning: 1 warning emitted
 
diff --git a/tests/ui/resolve/unused-macro-import.rs b/tests/ui/resolve/unused-macro-import.rs
new file mode 100644
index 00000000000..e85f7a43993
--- /dev/null
+++ b/tests/ui/resolve/unused-macro-import.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+
+#![warn(unused_imports)]
+
+#[macro_export]
+macro_rules! mac { () => {} }
+
+fn main() {
+    // Unused, `mac` as `macro_rules!` is already in scope and has higher priority.
+    use crate::mac; //~ WARN unused import: `crate::mac`
+
+    mac!();
+}
diff --git a/tests/ui/resolve/unused-macro-import.stderr b/tests/ui/resolve/unused-macro-import.stderr
new file mode 100644
index 00000000000..5f9813808a0
--- /dev/null
+++ b/tests/ui/resolve/unused-macro-import.stderr
@@ -0,0 +1,14 @@
+warning: unused import: `crate::mac`
+  --> $DIR/unused-macro-import.rs:10:9
+   |
+LL |     use crate::mac;
+   |         ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-macro-import.rs:3:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/simd/auxiliary/simd-lane-limit.rs b/tests/ui/simd/auxiliary/simd-lane-limit.rs
new file mode 100644
index 00000000000..dde6b880c62
--- /dev/null
+++ b/tests/ui/simd/auxiliary/simd-lane-limit.rs
@@ -0,0 +1,5 @@
+#![feature(rustc_attrs, repr_simd)]
+
+#[repr(simd, packed)]
+#[rustc_simd_monomorphize_lane_limit = "8"]
+pub struct Simd<T, const N: usize>(pub [T; N]);
diff --git a/tests/ui/simd/monomorphize-too-long.rs b/tests/ui/simd/monomorphize-too-long.rs
index 4fac987b0b5..9c837415191 100644
--- a/tests/ui/simd/monomorphize-too-long.rs
+++ b/tests/ui/simd/monomorphize-too-long.rs
@@ -6,7 +6,5 @@
 struct Simd<T, const N: usize>([T; N]);
 
 fn main() {
-    let _too_big = Simd([1_u16; 54321]);
+    let _too_big = Simd([1_u16; 54321]); //~ ERROR the SIMD type `Simd<u16, 54321>` has more elements than the limit 32768
 }
-
-//~? ERROR monomorphising SIMD type `Simd<u16, 54321>` of length greater than 32768
diff --git a/tests/ui/simd/monomorphize-too-long.stderr b/tests/ui/simd/monomorphize-too-long.stderr
index 978eef307ab..71bc78ef5c9 100644
--- a/tests/ui/simd/monomorphize-too-long.stderr
+++ b/tests/ui/simd/monomorphize-too-long.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<u16, 54321>` of length greater than 32768
+error: the SIMD type `Simd<u16, 54321>` has more elements than the limit 32768
+  --> $DIR/monomorphize-too-long.rs:9:9
+   |
+LL |     let _too_big = Simd([1_u16; 54321]);
+   |         ^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/simd/monomorphize-zero-length.rs b/tests/ui/simd/monomorphize-zero-length.rs
index d38870c572d..f956197a61c 100644
--- a/tests/ui/simd/monomorphize-zero-length.rs
+++ b/tests/ui/simd/monomorphize-zero-length.rs
@@ -6,7 +6,5 @@
 struct Simd<T, const N: usize>([T; N]);
 
 fn main() {
-    let _empty = Simd([1.0; 0]);
+    let _empty = Simd([1.0; 0]); //~ ERROR the SIMD type `Simd<f64, 0>` has zero elements
 }
-
-//~? ERROR monomorphising SIMD type `Simd<f64, 0>` of zero length
diff --git a/tests/ui/simd/monomorphize-zero-length.stderr b/tests/ui/simd/monomorphize-zero-length.stderr
index 738c20fe51a..66f26d95c9d 100644
--- a/tests/ui/simd/monomorphize-zero-length.stderr
+++ b/tests/ui/simd/monomorphize-zero-length.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<f64, 0>` of zero length
+error: the SIMD type `Simd<f64, 0>` has zero elements
+  --> $DIR/monomorphize-zero-length.rs:9:9
+   |
+LL |     let _empty = Simd([1.0; 0]);
+   |         ^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.rs b/tests/ui/simd/simd-lane-limit-err-npow2.rs
new file mode 100644
index 00000000000..d5c5c92e953
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err-npow2.rs
@@ -0,0 +1,12 @@
+//@ build-fail
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+    // test non-power-of-two, since #[repr(simd, packed)] has unusual layout
+    let _x: Simd<i32, 24> = Simd([0; 24]);
+    //~^ ERROR the SIMD type `simd::Simd<i32, 24>` has more elements than the limit 8
+}
diff --git a/tests/ui/simd/simd-lane-limit-err-npow2.stderr b/tests/ui/simd/simd-lane-limit-err-npow2.stderr
new file mode 100644
index 00000000000..fff26c4c1c1
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err-npow2.stderr
@@ -0,0 +1,8 @@
+error: the SIMD type `simd::Simd<i32, 24>` has more elements than the limit 8
+  --> $DIR/simd-lane-limit-err-npow2.rs:10:9
+   |
+LL |     let _x: Simd<i32, 24> = Simd([0; 24]);
+   |         ^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/simd/simd-lane-limit-err.rs b/tests/ui/simd/simd-lane-limit-err.rs
new file mode 100644
index 00000000000..00390bdbdaf
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err.rs
@@ -0,0 +1,11 @@
+//@ build-fail
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+    let _x: Simd<i32, 16> = Simd([0; 16]);
+    //~^ ERROR the SIMD type `simd::Simd<i32, 16>` has more elements than the limit 8
+}
diff --git a/tests/ui/simd/simd-lane-limit-err.stderr b/tests/ui/simd/simd-lane-limit-err.stderr
new file mode 100644
index 00000000000..3f2eaeda2d4
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-err.stderr
@@ -0,0 +1,8 @@
+error: the SIMD type `simd::Simd<i32, 16>` has more elements than the limit 8
+  --> $DIR/simd-lane-limit-err.rs:9:9
+   |
+LL |     let _x: Simd<i32, 16> = Simd([0; 16]);
+   |         ^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/simd/simd-lane-limit-ok.rs b/tests/ui/simd/simd-lane-limit-ok.rs
new file mode 100644
index 00000000000..52fd3158440
--- /dev/null
+++ b/tests/ui/simd/simd-lane-limit-ok.rs
@@ -0,0 +1,14 @@
+//@ build-pass
+//@ aux-crate:simd=simd-lane-limit.rs
+
+extern crate simd;
+
+use simd::Simd;
+
+fn main() {
+    let _x: Simd<i32, 4> = Simd([0; 4]);
+    let _y: Simd<i32, 8> = Simd([0; 8]);
+
+    // test non-power-of-two, since #[repr(simd, packed)] has unusual layout
+    let _z: Simd<i32, 6> = Simd([0; 6]);
+}
diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.rs b/tests/ui/simd/type-generic-monomorphisation-empty.rs
index c08dc9fe3df..7c43b8914da 100644
--- a/tests/ui/simd/type-generic-monomorphisation-empty.rs
+++ b/tests/ui/simd/type-generic-monomorphisation-empty.rs
@@ -6,7 +6,5 @@
 struct Simd<const N: usize>([f32; N]);
 
 fn main() {
-    let _ = Simd::<0>([]);
+    let _empty = Simd::<0>([]); //~ ERROR the SIMD type `Simd<0>` has zero elements
 }
-
-//~? ERROR monomorphising SIMD type `Simd<0>` of zero length
diff --git a/tests/ui/simd/type-generic-monomorphisation-empty.stderr b/tests/ui/simd/type-generic-monomorphisation-empty.stderr
index fc294607ae3..450db7e47db 100644
--- a/tests/ui/simd/type-generic-monomorphisation-empty.stderr
+++ b/tests/ui/simd/type-generic-monomorphisation-empty.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<0>` of zero length
+error: the SIMD type `Simd<0>` has zero elements
+  --> $DIR/type-generic-monomorphisation-empty.rs:9:9
+   |
+LL |     let _empty = Simd::<0>([]);
+   |         ^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.rs b/tests/ui/simd/type-generic-monomorphisation-oversized.rs
index efe3480317c..73a1f00e8c7 100644
--- a/tests/ui/simd/type-generic-monomorphisation-oversized.rs
+++ b/tests/ui/simd/type-generic-monomorphisation-oversized.rs
@@ -6,7 +6,6 @@
 struct Simd<const N: usize>([f32; N]);
 
 fn main() {
-    let _ = Simd::<65536>([0.; 65536]);
+    let _x = Simd::<65536>([0.; 65536]);
+    //~^ ERROR the SIMD type `Simd<65536>` has more elements than the limit 32768
 }
-
-//~? ERROR monomorphising SIMD type `Simd<65536>` of length greater than 32768
diff --git a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
index 39ff36799cc..0065049abd6 100644
--- a/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
+++ b/tests/ui/simd/type-generic-monomorphisation-oversized.stderr
@@ -1,4 +1,8 @@
-error: monomorphising SIMD type `Simd<65536>` of length greater than 32768
+error: the SIMD type `Simd<65536>` has more elements than the limit 32768
+  --> $DIR/type-generic-monomorphisation-oversized.rs:9:9
+   |
+LL |     let _x = Simd::<65536>([0.; 65536]);
+   |         ^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/incorrect-variant-literal.svg b/tests/ui/suggestions/incorrect-variant-literal.svg
index 2cab1f4b60f..4b952325cf7 100644
--- a/tests/ui/suggestions/incorrect-variant-literal.svg
+++ b/tests/ui/suggestions/incorrect-variant-literal.svg
@@ -1,7 +1,7 @@
 <svg width="886px" height="9524px" xmlns="http://www.w3.org/2000/svg">
   <style>
     .fg { fill: #AAAAAA }
-    .bg { background: #000000 }
+    .bg { fill: #000000 }
     .fg-ansi256-009 { fill: #FF5555 }
     .fg-ansi256-010 { fill: #55FF55 }
     .fg-ansi256-012 { fill: #5555FF }
diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr
index 1084ea7c9e0..c3cf7e13987 100644
--- a/tests/ui/suggestions/issue-97760.stderr
+++ b/tests/ui/suggestions/issue-97760.stderr
@@ -1,11 +1,8 @@
 error[E0277]: `<impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-97760.rs:4:20
+  --> $DIR/issue-97760.rs:4:19
    |
 LL |         println!("{x}");
-   |                   -^-
-   |                   ||
-   |                   |`<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter
-   |                   required by this formatting parameter
+   |                   ^^^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter
    |
    = help: the trait `std::fmt::Display` is not implemented for `<impl IntoIterator as IntoIterator>::Item`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
diff --git a/tests/ui/suggestions/non_copy_move_out_of_tuple.rs b/tests/ui/suggestions/non_copy_move_out_of_tuple.rs
new file mode 100644
index 00000000000..baf15dba33a
--- /dev/null
+++ b/tests/ui/suggestions/non_copy_move_out_of_tuple.rs
@@ -0,0 +1,8 @@
+// Regression test for #146537.
+
+struct NonCopy;
+fn main() {
+    let tuple = &(NonCopy,);
+    let b: NonCopy;
+    (b,) = *tuple; //~ ERROR: cannot move out of `tuple.0` which is behind a shared reference [E0507]
+}
diff --git a/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr b/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr
new file mode 100644
index 00000000000..62f24324fcc
--- /dev/null
+++ b/tests/ui/suggestions/non_copy_move_out_of_tuple.stderr
@@ -0,0 +1,26 @@
+error[E0507]: cannot move out of `tuple.0` which is behind a shared reference
+  --> $DIR/non_copy_move_out_of_tuple.rs:7:12
+   |
+LL |     (b,) = *tuple;
+   |      -     ^^^^^^
+   |      |
+   |      data moved here
+   |      move occurs because the place has type `NonCopy`, which does not implement the `Copy` trait
+   |
+note: if `NonCopy` implemented `Clone`, you could clone the value
+  --> $DIR/non_copy_move_out_of_tuple.rs:3:1
+   |
+LL | struct NonCopy;
+   | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     (b,) = *tuple;
+   |      - you could clone this value
+help: consider removing the dereference here
+   |
+LL -     (b,) = *tuple;
+LL +     (b,) = tuple;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs
index 6567f275240..2f108daf1e5 100644
--- a/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs
+++ b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs
@@ -1,7 +1,7 @@
 //@ compile-flags: -Znext-solver
 //@ check-pass
 
-// Fixes a regression in icu_provider_adaptors where we weren't normalizing the
+// Fixes a regression in icu_provider_adapters where we weren't normalizing the
 // return type of a function type before performing a `Ty::builtin_deref` call,
 // leading to an ICE.
 
diff --git a/tests/ui/traits/next-solver/writeback-predicate-bound-region.rs b/tests/ui/traits/next-solver/writeback-predicate-bound-region.rs
new file mode 100644
index 00000000000..a7ed5dbcf08
--- /dev/null
+++ b/tests/ui/traits/next-solver/writeback-predicate-bound-region.rs
@@ -0,0 +1,14 @@
+//@ edition: 2024
+//@ check-pass
+//@ compile-flags: -Znext-solver
+
+// This previously ICE'd during writeback when resolving
+// the stalled coroutine predicate due to its bound lifetime.
+
+trait Trait<'a> {}
+impl<'a, T: Send> Trait<'a> for T {}
+
+fn is_trait<T: for<'a> Trait<'a>>(_: T) {}
+fn main() {
+    is_trait(async {})
+}
diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs
new file mode 100644
index 00000000000..5541c5267f3
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs
@@ -0,0 +1,19 @@
+//! Regression test for ICE #139556
+
+#![feature(type_alias_impl_trait)]
+
+trait T {}
+
+type Alias<'a> = impl T;
+
+struct S;
+impl<'a> T for &'a S {}
+
+#[define_opaque(Alias)]
+fn with_positive(fun: impl Fn(Alias<'_>)) {
+//~^ WARN: function cannot return without recursing
+    with_positive(|&n| ());
+    //~^ ERROR: cannot move out of a shared reference
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr
new file mode 100644
index 00000000000..e1fdd222ee1
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr
@@ -0,0 +1,30 @@
+warning: function cannot return without recursing
+  --> $DIR/recursive-drop-elaboration-2.rs:13:1
+   |
+LL | fn with_positive(fun: impl Fn(Alias<'_>)) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     with_positive(|&n| ());
+   |     ---------------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/recursive-drop-elaboration-2.rs:15:20
+   |
+LL |     with_positive(|&n| ());
+   |                    ^-
+   |                     |
+   |                     data moved here
+   |                     move occurs because `n` has type `S`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     with_positive(|&n| ());
+LL +     with_positive(|n| ());
+   |
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs
new file mode 100644
index 00000000000..dd28732ebb2
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs
@@ -0,0 +1,24 @@
+//! Regression test for #122904.
+
+#![feature(type_alias_impl_trait)]
+
+trait T {}
+
+type Alias<'a> = impl T;
+
+struct S;
+impl<'a> T for &'a S {}
+
+#[define_opaque(Alias)]
+fn with_positive(fun: impl Fn(Alias<'_>)) {
+//~^ WARN: function cannot return without recursing
+    with_positive(|&n| ());
+    //~^ ERROR: cannot move out of a shared reference
+}
+
+#[define_opaque(Alias)]
+fn main(_: Alias<'_>) {
+//~^ ERROR: `main` function has wrong type [E0580]
+    with_positive(|&a| ());
+    //~^ ERROR: cannot move out of a shared reference
+}
diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr
new file mode 100644
index 00000000000..8b5dc950afd
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr
@@ -0,0 +1,58 @@
+warning: function cannot return without recursing
+  --> $DIR/recursive-drop-elaboration.rs:13:1
+   |
+LL | fn with_positive(fun: impl Fn(Alias<'_>)) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     with_positive(|&n| ());
+   |     ---------------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/recursive-drop-elaboration.rs:15:20
+   |
+LL |     with_positive(|&n| ());
+   |                    ^-
+   |                     |
+   |                     data moved here
+   |                     move occurs because `n` has type `S`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     with_positive(|&n| ());
+LL +     with_positive(|n| ());
+   |
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/recursive-drop-elaboration.rs:22:20
+   |
+LL |     with_positive(|&a| ());
+   |                    ^-
+   |                     |
+   |                     data moved here
+   |                     move occurs because `a` has type `S`, which does not implement the `Copy` trait
+   |
+help: consider removing the borrow
+   |
+LL -     with_positive(|&a| ());
+LL +     with_positive(|a| ());
+   |
+
+error[E0580]: `main` function has wrong type
+  --> $DIR/recursive-drop-elaboration.rs:20:1
+   |
+LL | type Alias<'a> = impl T;
+   |                  ------ the found opaque type
+...
+LL | fn main(_: Alias<'_>) {
+   | ^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
+   |
+   = note: expected signature `fn()`
+              found signature `for<'a> fn(Alias<'a>)`
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0507, E0580.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/crashes/125185.rs b/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.rs
index e77666ca73d..c0fb9007865 100644
--- a/tests/crashes/125185.rs
+++ b/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.rs
@@ -1,4 +1,4 @@
-//@ known-bug: rust-lang/rust#125185
+//! Regression test for #125185
 //@ compile-flags: -Zvalidate-mir
 
 #![feature(type_alias_impl_trait)]
@@ -10,6 +10,7 @@ struct A;
 #[define_opaque(Foo)]
 const fn foo() -> Foo {
     value()
+    //~^ ERROR: cannot find function `value` in this scope
 }
 
 const VALUE: Foo = foo();
diff --git a/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr b/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr
new file mode 100644
index 00000000000..1cb33eabd90
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/type-error-drop-elaboration.stderr
@@ -0,0 +1,12 @@
+error[E0425]: cannot find function `value` in this scope
+  --> $DIR/type-error-drop-elaboration.rs:12:5
+   |
+LL |     value()
+   |     ^^^^^ help: a constant with a similar name exists: `VALUE`
+...
+LL | const VALUE: Foo = foo();
+   | ------------------------- similarly named constant `VALUE` defined here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/type-inference/box_has_sigdrop.rs b/tests/ui/type-inference/box_has_sigdrop.rs
new file mode 100644
index 00000000000..3e801197a78
--- /dev/null
+++ b/tests/ui/type-inference/box_has_sigdrop.rs
@@ -0,0 +1,9 @@
+//@ should-fail
+//@ compile-flags: -Wrust-2021-incompatible-closure-captures
+// Inference, canonicalization, and significant drops should work nicely together.
+// Related issue: #86868
+
+fn main() {
+    let mut state = 0;
+    Box::new(move || state)
+}
diff --git a/tests/ui/type-inference/box_has_sigdrop.stderr b/tests/ui/type-inference/box_has_sigdrop.stderr
new file mode 100644
index 00000000000..b61b6322c10
--- /dev/null
+++ b/tests/ui/type-inference/box_has_sigdrop.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/box_has_sigdrop.rs:8:5
+   |
+LL | fn main() {
+   |          - expected `()` because of default return type
+LL |     let mut state = 0;
+LL |     Box::new(move || state)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
+   |     |
+   |     expected `()`, found `Box<{closure@box_has_sigdrop.rs:8:14}>`
+   |
+   = note: expected unit type `()`
+                 found struct `Box<{closure@$DIR/box_has_sigdrop.rs:8:14: 8:21}>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type-inference/has_sigdrop.rs b/tests/ui/type-inference/dropper_has_sigdrop.rs
index c3d835cfe16..c3d835cfe16 100644
--- a/tests/ui/type-inference/has_sigdrop.rs
+++ b/tests/ui/type-inference/dropper_has_sigdrop.rs
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index 96d85d1e7c1..27cba656030 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -398,7 +398,8 @@ mod expressions {
         let expr;
         format_arguments::new_const(&[]);
         {
-            super let args = [format_argument::new_display(&expr)];
+            super let args = (&expr,);
+            super let args = [format_argument::new_display(args.0)];
             format_arguments::new_v1(&[""], &args)
         };
     }
diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout
index 0792dc10e94..233c9f1c91b 100644
--- a/tests/ui/unpretty/flattened-format-args.stdout
+++ b/tests/ui/unpretty/flattened-format-args.stdout
@@ -11,7 +11,8 @@ fn main() {
     // Should flatten to println!("a 123 b {x} xyz\n"):
     {
         ::std::io::_print({
-                super let args = [format_argument::new_display(&x)];
+                super let args = (&x,);
+                super let args = [format_argument::new_display(args.0)];
                 format_arguments::new_v1(&["a 123 b ", " xyz\n"], &args)
             });
     };
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr
index c3147558b03..afef024e1b9 100644
--- a/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr
+++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr
@@ -6,7 +6,7 @@ LL | impl aux::Trait for LocalTy {}
    |
    = note: conflicting implementation in crate `unstable_impl_coherence_aux`:
            - impl<T> Trait for T
-             where unstable feature: `foo`;
+             where feature(foo) is enabled;
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr
index c3147558b03..afef024e1b9 100644
--- a/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr
+++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr
@@ -6,7 +6,7 @@ LL | impl aux::Trait for LocalTy {}
    |
    = note: conflicting implementation in crate `unstable_impl_coherence_aux`:
            - impl<T> Trait for T
-             where unstable feature: `foo`;
+             where feature(foo) is enabled;
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr
index c2bb10f043b..840af730154 100644
--- a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr
+++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr
@@ -7,7 +7,7 @@ LL |     vec![].foo();
    = note: multiple `impl`s satisfying `Vec<_>: Trait` found in the `unstable_impl_method_selection_aux` crate:
            - impl Trait for Vec<u32>;
            - impl Trait for Vec<u64>
-             where unstable feature: `bar`;
+             where feature(bar) is enabled;
 
 error: aborting due to 1 previous error