about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock88
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml35
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock166
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml12
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/bench.rs47
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/config.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/main.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/path.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/config.txt10
-rw-r--r--compiler/rustc_codegen_cranelift/patches/bcryptprimitives.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh7
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs205
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs37
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs24
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs46
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs20
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs230
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs61
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp23
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_mir_build/messages.ftl5
-rw-r--r--compiler/rustc_mir_build/src/errors.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs57
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs32
-rw-r--r--compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs36
-rw-r--r--compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs36
-rw-r--r--compiler/rustc_target/src/target_features.rs1007
-rw-r--r--library/Cargo.lock31
-rw-r--r--library/Cargo.toml2
-rw-r--r--library/alloc/src/alloc.rs2
-rw-r--r--library/alloc/src/boxed.rs24
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/macros.rs5
-rw-r--r--library/alloc/tests/vec.rs39
m---------library/backtrace0
-rw-r--r--library/core/src/iter/adapters/flatten.rs34
-rw-r--r--library/core/src/iter/sources/from_fn.rs2
-rw-r--r--library/core/src/iter/sources/successors.rs1
-rw-r--r--library/core/src/slice/mod.rs8
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/src/sys/pal/windows/os.rs5
-rw-r--r--src/bootstrap/src/utils/helpers.rs2
-rw-r--r--src/doc/rustc-dev-guide/README.md61
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/Cargo.lock430
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/Cargo.toml10
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/README.md4
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/src/main.rs32
-rw-r--r--src/doc/rustc-dev-guide/josh-sync/src/sync.rs234
-rw-r--r--src/doc/rustc-dev-guide/rust-version1
-rw-r--r--src/doc/rustc-dev-guide/src/SUMMARY.md9
-rw-r--r--src/doc/rustc-dev-guide/src/early-late-bound-params/early-late-bound-implementation-nuances.md197
-rw-r--r--src/doc/rustc-dev-guide/src/early-late-bound-params/turbofishing-and-early-late-bound.md125
-rw-r--r--src/doc/rustc-dev-guide/src/early_late_parameters.md424
-rw-r--r--src/doc/rustc-dev-guide/src/external-repos.md38
-rw-r--r--src/doc/rustc-dev-guide/src/generic_parameters_summary.md40
-rw-r--r--src/doc/rustc-dev-guide/src/method-lookup.md4
-rw-r--r--src/doc/rustc-dev-guide/src/solve/normalization.md6
-rw-r--r--src/doc/rustc-dev-guide/src/solve/opaque-types.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/compiletest.md40
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md13
-rw-r--r--src/doc/rustc-dev-guide/src/traits/chalk.md4
-rw-r--r--src/doc/rustc-dev-guide/src/ty_module/early_binder.md8
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/doc/rustc/src/platform-support.md12
-rw-r--r--src/doc/rustc/src/platform-support/mips-mti-none-elf.md31
-rw-r--r--src/doc/rustc/src/platform-support/uwp-windows-msvc.md52
-rw-r--r--src/tools/build-manifest/src/main.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr17
-rw-r--r--src/tools/compiletest/src/header.rs12
-rw-r--r--src/tools/compiletest/src/header/tests.rs53
-rw-r--r--src/tools/rustbook/Cargo.lock21
-rw-r--r--src/tools/tidy/src/deps.rs13
-rw-r--r--tests/assembly/targets/targets-elf.rs8
-rw-r--r--tests/assembly/targets/targets-macho.rs2
-rw-r--r--tests/codegen/target-feature-overrides.rs8
-rw-r--r--tests/codegen/tied-features-strength.rs5
-rw-r--r--tests/crashes/134336.rs11
-rw-r--r--tests/crashes/134355.rs6
-rw-r--r--tests/crashes/134479.rs24
-rw-r--r--tests/crashes/134587.rs27
-rw-r--r--tests/crashes/134615.rs16
-rw-r--r--tests/crashes/134641.rs13
-rw-r--r--tests/crashes/134654.rs12
-rw-r--r--tests/crashes/134838.rs14
-rw-r--r--tests/crashes/134905.rs16
-rw-r--r--tests/crashes/135020.rs11
-rw-r--r--tests/crashes/135039.rs34
-rw-r--r--tests/mir-opt/box_expr.rs5
-rw-r--r--tests/mir-opt/building/uniform_array_move_out.rs16
-rw-r--r--tests/mir-opt/const_prop/boxes.rs6
-rw-r--r--tests/mir-opt/issue_62289.rs7
-rw-r--r--tests/run-make/simd-ffi/rmake.rs2
-rw-r--r--tests/ui/attributes/rustc-box.rs18
-rw-r--r--tests/ui/attributes/rustc-box.stderr34
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr2
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.feature.stderr2
-rw-r--r--tests/ui/check-cfg/exhaustive-names-values.full.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/coroutine/issue-105084.rs5
-rw-r--r--tests/ui/coroutine/issue-105084.stderr16
-rw-r--r--tests/ui/lint/unused/unused-allocation.rs2
-rw-r--r--tests/ui/lint/unused/unused-allocation.stderr16
-rw-r--r--tests/ui/macros/vec-macro-in-pattern.rs4
-rw-r--r--tests/ui/macros/vec-macro-in-pattern.stderr31
-rw-r--r--tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs10
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr6
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs10
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr7
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr8
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-attribute.rs2
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-attribute.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-flag.stderr2
-rw-r--r--tests/ui/unpretty/box.rs7
-rw-r--r--tests/ui/unpretty/box.stdout100
133 files changed, 3041 insertions, 1884 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a1365c2d202..fca4469803b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -285,9 +285,9 @@ dependencies = [
 
 [[package]]
 name = "bstr"
-version = "1.11.1"
+version = "1.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8"
+checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
 dependencies = [
  "memchr",
  "regex-automata 0.4.9",
@@ -533,7 +533,7 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -564,7 +564,7 @@ dependencies = [
  "rustc_tools_util",
  "serde",
  "serde_json",
- "syn 2.0.93",
+ "syn 2.0.94",
  "tempfile",
  "termize",
  "tokio",
@@ -674,7 +674,7 @@ dependencies = [
  "nom",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -899,7 +899,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -910,7 +910,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -947,7 +947,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -968,7 +968,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -978,7 +978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
 dependencies = [
  "derive_builder_core",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -990,7 +990,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -1068,7 +1068,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -1365,7 +1365,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -1599,7 +1599,7 @@ dependencies = [
  "markup5ever",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -1788,7 +1788,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -2744,7 +2744,7 @@ dependencies = [
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -3154,7 +3154,7 @@ dependencies = [
  "rinja_parser",
  "rustc-hash 2.1.0",
  "serde",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -3499,6 +3499,7 @@ name = "rustc_codegen_llvm"
 version = "0.0.0"
 dependencies = [
  "bitflags",
+ "gimli 0.30.0",
  "itertools",
  "libc",
  "measureme",
@@ -3794,7 +3795,7 @@ dependencies = [
  "fluent-syntax",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "unic-langid",
 ]
 
@@ -3929,7 +3930,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -4077,7 +4078,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "synstructure",
 ]
 
@@ -4665,7 +4666,7 @@ version = "0.0.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "synstructure",
 ]
 
@@ -4754,7 +4755,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -4891,7 +4892,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -5008,9 +5009,9 @@ dependencies = [
 
 [[package]]
 name = "spdx"
-version = "0.10.7"
+version = "0.10.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bae30cc7bfe3656d60ee99bf6836f472b0c53dddcbf335e253329abb16e535a2"
+checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193"
 dependencies = [
  "smallvec",
 ]
@@ -5149,9 +5150,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.93"
+version = "2.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
+checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5166,7 +5167,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -5203,12 +5204,13 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.14.0"
+version = "3.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
+checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "getrandom",
  "once_cell",
  "rustix",
  "windows-sys 0.59.0",
@@ -5308,7 +5310,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -5319,7 +5321,7 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -5520,7 +5522,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -5691,7 +5693,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b"
 dependencies = [
  "proc-macro-hack",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "unic-langid-impl",
 ]
 
@@ -5897,7 +5899,7 @@ dependencies = [
  "log",
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "wasm-bindgen-shared",
 ]
 
@@ -5919,7 +5921,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -6101,7 +6103,7 @@ dependencies = [
  "rayon",
  "serde",
  "serde_json",
- "syn 2.0.93",
+ "syn 2.0.94",
  "windows-metadata",
 ]
 
@@ -6134,7 +6136,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -6145,7 +6147,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -6424,7 +6426,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "synstructure",
 ]
 
@@ -6446,7 +6448,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
 
 [[package]]
@@ -6466,7 +6468,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
  "synstructure",
 ]
 
@@ -6489,5 +6491,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.93",
+ "syn 2.0.94",
 ]
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 2ee94146c1a..a8333df77e6 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -56,11 +56,6 @@ jobs:
           - os: macos-latest
             env:
               TARGET_TRIPLE: x86_64-apple-darwin
-          # cross-compile from Linux to Windows using mingw
-          - os: ubuntu-latest
-            env:
-              TARGET_TRIPLE: x86_64-pc-windows-gnu
-            apt_deps: gcc-mingw-w64-x86-64 wine-stable
           - os: ubuntu-latest
             env:
               TARGET_TRIPLE: aarch64-unknown-linux-gnu
@@ -113,15 +108,6 @@ jobs:
     - name: Prepare dependencies
       run: ./y.sh prepare
 
-    # The Wine version shipped with Ubuntu 22.04 doesn't implement bcryptprimitives.dll
-    - name: Build bcryptprimitives.dll shim for Wine
-      if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
-      run: |
-        rustup target add x86_64-pc-windows-gnu
-        mkdir wine_shims
-        rustc patches/bcryptprimitives.rs -Copt-level=3 -Clto=fat --out-dir wine_shims --target x86_64-pc-windows-gnu
-        echo "WINEPATH=$(pwd)/wine_shims" >> $GITHUB_ENV
-
     - name: Build
       run: ./y.sh build --sysroot none
 
@@ -135,9 +121,6 @@ jobs:
 
     # This is roughly config rust-lang/rust uses for testing
     - name: Test with LLVM sysroot
-      # Skip native x86_64-pc-windows-gnu. It is way too slow and cross-compiled
-      # x86_64-pc-windows-gnu covers at least part of the tests.
-      if: matrix.os != 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
       env:
         TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
       run: ./y.sh test --sysroot llvm --no-unstable-features
@@ -215,10 +198,6 @@ jobs:
           - os: macos-latest
             env:
               TARGET_TRIPLE: aarch64-apple-darwin
-          # cross-compile from Linux to Windows using mingw
-          - os: ubuntu-latest
-            env:
-              TARGET_TRIPLE: x86_64-pc-windows-gnu
           - os: windows-latest
             env:
               TARGET_TRIPLE: x86_64-pc-windows-msvc
@@ -243,12 +222,6 @@ jobs:
       if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
       run: rustup set default-host x86_64-apple-darwin
 
-    - name: Install MinGW toolchain
-      if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
-      run: |
-        sudo apt-get update
-        sudo apt-get install -y gcc-mingw-w64-x86-64
-
     - name: Prepare dependencies
       run: ./y.sh prepare
 
@@ -262,19 +235,11 @@ jobs:
       run: tar cvfJ cg_clif.tar.xz dist
 
     - name: Upload prebuilt cg_clif
-      if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
       uses: actions/upload-artifact@v4
       with:
         name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
         path: cg_clif.tar.xz
 
-    - name: Upload prebuilt cg_clif (cross compile)
-      if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
-      uses: actions/upload-artifact@v4
-      with:
-        name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
-        path: cg_clif.tar.xz
-
   release:
     runs-on: ubuntu-latest
     timeout-minutes: 10
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index d81e7214961..ec71370ef9e 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -3,22 +3,16 @@
 version = 4
 
 [[package]]
-name = "ahash"
-version = "0.8.11"
+name = "allocator-api2"
+version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
-dependencies = [
- "cfg-if",
- "once_cell",
- "version_check",
- "zerocopy",
-]
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
 name = "anyhow"
-version = "1.0.86"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
 
 [[package]]
 name = "arbitrary"
@@ -37,6 +31,9 @@ name = "bumpalo"
 version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+dependencies = [
+ "allocator-api2",
+]
 
 [[package]]
 name = "cfg-if"
@@ -46,24 +43,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1"
+checksum = "ac89549be94911dd0e839b4a7db99e9ed29c17517e1c026f61066884c168aa3c"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-bitset"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156"
+checksum = "b9bd49369f76c77e34e641af85d0956869237832c118964d08bf5f51f210875a"
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b"
+checksum = "fd96ce9cf8efebd7f5ab8ced5a0ce44250280bbae9f593d74a6d7effc3582a35"
 dependencies = [
  "bumpalo",
  "cranelift-bforest",
@@ -74,7 +71,7 @@ dependencies = [
  "cranelift-entity",
  "cranelift-isle",
  "gimli",
- "hashbrown",
+ "hashbrown 0.14.5",
  "log",
  "regalloc2",
  "rustc-hash",
@@ -85,42 +82,42 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7"
+checksum = "5a68e358827afe4bfb6239fcbf6fbd5ac56206ece8a99c8f5f9bbd518773281a"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895"
+checksum = "e184c9767afbe73d50c55ec29abcf4c32f9baf0d9d22b86d58c4d55e06dee181"
 
 [[package]]
 name = "cranelift-control"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec"
+checksum = "5cc7664f2a66f053e33f149e952bb5971d138e3af637f5097727ed6dc0ed95dd"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96"
+checksum = "118597e3a9cf86c3556fa579a7a23b955fa18231651a52a77a2475d305a9cf84"
 dependencies = [
  "cranelift-bitset",
 ]
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e"
+checksum = "7638ea1efb069a0aa18d8ee67401b6b0d19f6bfe5de5e9ede348bfc80bb0d8c7"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -130,15 +127,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8"
+checksum = "15c53e1152a0b01c4ed2b1e0535602b8e86458777dd9d18b28732b16325c7dc0"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62699329d4ced20fe281fbaef45e11b473b7ab310491b4bdebcd8b818a8ef7fe"
+checksum = "36972cab12ff246afe8d45b6a427669cf814bd393c661e5e8a8dedc26a81c73f"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -156,9 +153,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f20b0b51ba962dac30fc7e812b86e4390d908acd4f59bcc8ac7610a8f3e0977"
+checksum = "11841b3f54ac480db1e8e8d5678ba901a13b387012d315e3f8fba3e7b7a80447"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -167,9 +164,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f"
+checksum = "7b7d8f895444fa52dd7bdd0bed11bf007a7fb43af65a6deac8fcc4094c6372f7"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -178,9 +175,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.114.0"
+version = "0.115.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee231640a7ecceedd0f1f2782d9288db6a6908cc70675ed9427e3bf0ea6daacd"
+checksum = "8e235ddfd19f100855ad03358c7ae0a13070c38a000701054cab46458cca6e81"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -213,6 +210,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
 
 [[package]]
+name = "foldhash"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
+
+[[package]]
 name = "gimli"
 version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -228,18 +231,24 @@ name = "hashbrown"
 version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
 dependencies = [
- "ahash",
+ "foldhash",
 ]
 
 [[package]]
 name = "indexmap"
-version = "2.2.6"
+version = "2.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
 dependencies = [
  "equivalent",
- "hashbrown",
+ "hashbrown 0.15.2",
 ]
 
 [[package]]
@@ -281,27 +290,21 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "object"
-version = "0.36.2"
+version = "0.36.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
 dependencies = [
  "crc32fast",
- "hashbrown",
+ "hashbrown 0.15.2",
  "indexmap",
  "memchr",
 ]
 
 [[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
@@ -317,14 +320,15 @@ dependencies = [
 
 [[package]]
 name = "regalloc2"
-version = "0.10.2"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0"
+checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3"
 dependencies = [
- "hashbrown",
+ "allocator-api2",
+ "bumpalo",
+ "hashbrown 0.15.2",
  "log",
  "rustc-hash",
- "slice-group-by",
  "smallvec",
 ]
 
@@ -366,18 +370,18 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.210"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.210"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -385,12 +389,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "slice-group-by"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
-
-[[package]]
 name = "smallvec"
 version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -404,9 +402,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
 name = "syn"
-version = "2.0.70"
+version = "2.0.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -426,16 +424,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "27.0.0"
+version = "28.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad"
+checksum = "d40d7722b9e1fbeae135715710a8a2570b1e6cf72b74dd653962d89831c6c70d"
 dependencies = [
  "anyhow",
  "cfg-if",
@@ -524,23 +516,3 @@ name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "zerocopy"
-version = "0.7.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
-dependencies = [
- "zerocopy-derive",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.7.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index b2fed3c490e..82d2b6cb2c4 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.114.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
-cranelift-frontend = { version = "0.114.0" }
-cranelift-module = { version = "0.114.0" }
-cranelift-native = { version = "0.114.0" }
-cranelift-jit = { version = "0.114.0", optional = true }
-cranelift-object = { version = "0.114.0" }
+cranelift-codegen = { version = "0.115.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
+cranelift-frontend = { version = "0.115.0" }
+cranelift-module = { version = "0.115.0" }
+cranelift-native = { version = "0.115.0" }
+cranelift-jit = { version = "0.115.0", optional = true }
+cranelift-object = { version = "0.115.0" }
 target-lexicon = "0.12.0"
 gimli = { version = "0.31", default-features = false, features = ["write"] }
 object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
diff --git a/compiler/rustc_codegen_cranelift/build_system/bench.rs b/compiler/rustc_codegen_cranelift/build_system/bench.rs
index 73a0f325fc2..8359b7b5279 100644
--- a/compiler/rustc_codegen_cranelift/build_system/bench.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/bench.rs
@@ -16,11 +16,7 @@ static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
     "<none>",
 );
 
-pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
-    benchmark_simple_raytracer(dirs, bootstrap_host_compiler);
-}
-
-fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
+pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) {
     if std::process::Command::new("hyperfine").output().is_err() {
         eprintln!("Hyperfine not installed");
         eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine");
@@ -39,9 +35,9 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
     };
 
     eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
-    let cargo_clif = dirs
-        .dist_dir
-        .join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-"));
+    let cargo_clif = &compiler.cargo;
+    let rustc_clif = &compiler.rustc;
+    let rustflags = &compiler.rustflags.join("\x1f");
     let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml");
     let target_dir = dirs.build_dir.join("simple_raytracer");
 
@@ -56,22 +52,24 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
         target_dir = target_dir.display(),
     );
     let clif_build_cmd = format!(
-        "RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif",
+        "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif",
         cargo_clif = cargo_clif.display(),
+        rustc_clif = rustc_clif.display(),
         manifest_path = manifest_path.display(),
         target_dir = target_dir.display(),
     );
     let clif_build_opt_cmd = format!(
-        "RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt",
+        "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt",
         cargo_clif = cargo_clif.display(),
+        rustc_clif = rustc_clif.display(),
         manifest_path = manifest_path.display(),
         target_dir = target_dir.display(),
     );
 
-    let bench_compile_markdown = dirs.dist_dir.join("bench_compile.md");
+    let bench_compile_markdown = dirs.build_dir.join("bench_compile.md");
 
     let bench_compile = hyperfine_command(
-        1,
+        0,
         bench_runs,
         Some(&clean_cmd),
         &[
@@ -92,23 +90,14 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
 
     eprintln!("[BENCH RUN] ebobby/simple-raytracer");
 
-    let bench_run_markdown = dirs.dist_dir.join("bench_run.md");
-
-    let raytracer_cg_llvm = Path::new(".").join(get_file_name(
-        &bootstrap_host_compiler.rustc,
-        "raytracer_cg_llvm",
-        "bin",
-    ));
-    let raytracer_cg_clif = Path::new(".").join(get_file_name(
-        &bootstrap_host_compiler.rustc,
-        "raytracer_cg_clif",
-        "bin",
-    ));
-    let raytracer_cg_clif_opt = Path::new(".").join(get_file_name(
-        &bootstrap_host_compiler.rustc,
-        "raytracer_cg_clif_opt",
-        "bin",
-    ));
+    let bench_run_markdown = dirs.build_dir.join("bench_run.md");
+
+    let raytracer_cg_llvm =
+        Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin"));
+    let raytracer_cg_clif =
+        Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin"));
+    let raytracer_cg_clif_opt =
+        Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin"));
     let mut bench_run = hyperfine_command(
         0,
         bench_runs,
diff --git a/compiler/rustc_codegen_cranelift/build_system/config.rs b/compiler/rustc_codegen_cranelift/build_system/config.rs
index ef540cf1f82..37bc4c5d782 100644
--- a/compiler/rustc_codegen_cranelift/build_system/config.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/config.rs
@@ -33,23 +33,3 @@ pub(crate) fn get_bool(name: &str) -> bool {
         true
     }
 }
-
-pub(crate) fn get_value(name: &str) -> Option<String> {
-    let values = load_config_file()
-        .into_iter()
-        .filter(|(key, _)| key == name)
-        .map(|(_, val)| val)
-        .collect::<Vec<_>>();
-    if values.is_empty() {
-        None
-    } else if values.len() == 1 {
-        if values[0].is_none() {
-            eprintln!("Config `{}` missing value", name);
-            process::exit(1);
-        }
-        values.into_iter().next().unwrap()
-    } else {
-        eprintln!("Config `{}` given multiple values: {:?}", name, values);
-        process::exit(1);
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs
index 99e6146657f..3ff9751a3ef 100644
--- a/compiler/rustc_codegen_cranelift/build_system/main.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/main.rs
@@ -156,10 +156,8 @@ fn main() {
         let cargo = rustc_info::get_cargo_path();
         let rustc = rustc_info::get_rustc_path();
         let rustdoc = rustc_info::get_rustdoc_path();
-        let triple = std::env::var("HOST_TRIPLE")
-            .ok()
-            .or_else(|| config::get_value("host"))
-            .unwrap_or_else(|| rustc_info::get_host_triple(&rustc));
+        let triple =
+            std::env::var("HOST_TRIPLE").unwrap_or_else(|_| rustc_info::get_host_triple(&rustc));
         Compiler {
             cargo,
             rustc,
@@ -170,10 +168,8 @@ fn main() {
             runner: vec![],
         }
     };
-    let target_triple = std::env::var("TARGET_TRIPLE")
-        .ok()
-        .or_else(|| config::get_value("target"))
-        .unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
+    let target_triple =
+        std::env::var("TARGET_TRIPLE").unwrap_or_else(|_| bootstrap_host_compiler.triple.clone());
 
     let dirs = path::Dirs {
         source_dir: current_dir.clone(),
@@ -247,7 +243,7 @@ fn main() {
             );
         }
         Command::Bench => {
-            build_sysroot::build_sysroot(
+            let compiler = build_sysroot::build_sysroot(
                 &dirs,
                 sysroot_kind,
                 &cg_clif_dylib,
@@ -255,7 +251,7 @@ fn main() {
                 rustup_toolchain_name.as_deref(),
                 target_triple,
             );
-            bench::benchmark(&dirs, &bootstrap_host_compiler);
+            bench::benchmark(&dirs, &compiler);
         }
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/build_system/path.rs b/compiler/rustc_codegen_cranelift/build_system/path.rs
index 20a81156b71..d6a6558b2be 100644
--- a/compiler/rustc_codegen_cranelift/build_system/path.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/path.rs
@@ -11,20 +11,11 @@ pub(crate) struct Dirs {
 
 #[doc(hidden)]
 #[derive(Debug, Copy, Clone)]
-pub(crate) enum PathBase {
+enum PathBase {
     Source,
     Build,
 }
 
-impl PathBase {
-    fn to_path(self, dirs: &Dirs) -> PathBuf {
-        match self {
-            PathBase::Source => dirs.source_dir.clone(),
-            PathBase::Build => dirs.build_dir.clone(),
-        }
-    }
-}
-
 #[derive(Debug, Copy, Clone)]
 pub(crate) struct RelPath {
     base: PathBase,
@@ -41,6 +32,9 @@ impl RelPath {
     }
 
     pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
-        self.base.to_path(dirs).join(self.suffix)
+        match self.base {
+            PathBase::Source => dirs.source_dir.join(self.suffix),
+            PathBase::Build => dirs.build_dir.join(self.suffix),
+        }
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt
index b63597f60fc..9808ad624e1 100644
--- a/compiler/rustc_codegen_cranelift/config.txt
+++ b/compiler/rustc_codegen_cranelift/config.txt
@@ -1,15 +1,5 @@
 # This file allows configuring the build system.
 
-# Which triple to produce a compiler toolchain for.
-#
-# Defaults to the default triple of rustc on the host system.
-#host = x86_64-unknown-linux-gnu
-
-# Which triple to build libraries (core/alloc/std/test/proc_macro) for.
-#
-# Defaults to `host`.
-#target = x86_64-unknown-linux-gnu
-
 # Disables cleaning of the sysroot dir. This will cause old compiled artifacts to be re-used when
 # the sysroot source hasn't changed. This is useful when the codegen backend hasn't been modified.
 # This option can be changed while the build system is already running for as long as sysroot
diff --git a/compiler/rustc_codegen_cranelift/patches/bcryptprimitives.rs b/compiler/rustc_codegen_cranelift/patches/bcryptprimitives.rs
deleted file mode 100644
index 4d186485aac..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/bcryptprimitives.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Shim for bcryptprimitives.dll. The Wine version shipped with Ubuntu 22.04
-// doesn't support it yet. Authored by @ChrisDenton
-
-#![crate_type = "cdylib"]
-#![allow(nonstandard_style)]
-
-#[no_mangle]
-pub unsafe extern "system" fn ProcessPrng(mut pbData: *mut u8, mut cbData: usize) -> i32 {
-    while cbData > 0 {
-        let size = core::cmp::min(cbData, u32::MAX as usize);
-        RtlGenRandom(pbData, size as u32);
-        cbData -= size;
-        pbData = pbData.add(size);
-    }
-    1
-}
-
-#[link(name = "advapi32")]
-extern "system" {
-    #[link_name = "SystemFunction036"]
-    pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
-}
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 8d935df4d1f..4b97f210579 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2024-12-06"
+channel = "nightly-2025-01-05"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
 profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index e291ec20464..442d61c6ade 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -123,12 +123,17 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same
 rm tests/ui/consts/issue-33537.rs # same
 rm tests/ui/consts/const-mut-refs-crate.rs # same
 rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift
+rm tests/ui/invalid-compile-flags/crate-type-flag.rs # warning about proc-macros and panic=abort
 
 # doesn't work due to the way the rustc test suite is invoked.
 # should work when using ./x.py test the way it is intended
 # ============================================================
 rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
+rm -r tests/run-make/strip # same
 rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source
+rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features
+rm -r tests/run-make/const-trait-stable-toolchain # same
+rm -r tests/run-make/incr-add-rust-src-component
 
 # genuine bugs
 # ============
@@ -196,5 +201,5 @@ index e7ae773ffa1d3..04bc2d7787da7 100644
 EOF
 
 echo "[TEST] rustc test suite"
-COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,ui,incremental}
+COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
 popd
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 4fc30b69123..fe578e44770 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -333,10 +333,9 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
 
     let mut builder =
         ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
-    // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
-    // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
-    // can easily double the amount of time necessary to perform linking.
-    builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false));
+    builder.per_function_section(
+        sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections),
+    );
     UnwindModule::new(ObjectModule::new(builder), true)
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index eaab3362c7e..9ca930e14da 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -287,7 +287,7 @@ fn dep_symbol_lookup_fn(
 
     let mut dylib_paths = Vec::new();
 
-    let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable].1;
+    let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable];
     // `used_crates` is in reverse postorder in terms of dependencies. Reverse the order here to
     // get a postorder which ensures that all dependencies of a dylib are loaded before the dylib
     // itself. This helps the dynamic linker to find dylibs not in the regular dynamic library
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 33726056cc1..6ff75f75d3b 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -136,7 +136,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
             fx.bcx.ins().jump(destination_block, &[]);
         }
         None => {
-            fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap());
+            fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
         }
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index e0ebe30752a..6d71b8e8aba 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -1136,7 +1136,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
         _ => {
             fx.tcx.dcx().span_err(span, format!("Unknown SIMD intrinsic {}", intrinsic));
             // Prevent verifier error
-            fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap());
+            fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
             return;
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index c38ef82e5b8..dc5d80e7a34 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -27,6 +27,8 @@ extern crate rustc_metadata;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
+#[macro_use]
+extern crate tracing;
 
 // This prevents duplicating functions and statics that are already part of the host rustc process.
 #[allow(unused_extern_crates)]
@@ -208,6 +210,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
         need_metadata_module: bool,
     ) -> Box<dyn Any> {
         tcx.dcx().abort_if_errors();
+        info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE));
         let config = self.config.clone().unwrap_or_else(|| {
             BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
                 .unwrap_or_else(|err| tcx.sess.dcx().fatal(err))
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index 56849cc8610..c896246866b 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -28,6 +28,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
 #[diag(codegen_gcc_forbidden_ctarget_feature)]
 pub(crate) struct ForbiddenCTargetFeature<'a> {
     pub feature: &'a str,
+    pub enabled: &'a str,
     pub reason: &'a str,
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 058a874501b..1994a2a3c53 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -1,9 +1,11 @@
+use std::iter::FromIterator;
+
 #[cfg(feature = "master")]
 use gccjit::Context;
 use rustc_codegen_ssa::codegen_attrs::check_tied_features;
 use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::bug;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::unord::UnordSet;
 use rustc_session::Session;
 use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
 use smallvec::{SmallVec, smallvec};
@@ -37,82 +39,137 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     let mut features = vec![];
 
     // Features implied by an implicit or explicit `--target`.
-    features.extend(
-        sess.target
-            .features
-            .split(',')
-            .filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
-            .map(String::from),
-    );
+    features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
 
     // -Ctarget-features
     let known_features = sess.target.rust_target_features();
     let mut featsmap = FxHashMap::default();
-    let feats = sess
-        .opts
-        .cg
-        .target_feature
-        .split(',')
-        .filter_map(|s| {
-            let enable_disable = match s.chars().next() {
-                None => return None,
-                Some(c @ ('+' | '-')) => c,
-                Some(_) => {
-                    if diagnostics {
-                        sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
-                    }
-                    return None;
-                }
-            };
 
-            // Get the backend feature name, if any.
-            // This excludes rustc-specific features, that do not get passed down to GCC.
-            let feature = backend_feature_name(s)?;
-            // Warn against use of GCC specific feature names on the CLI.
+    // Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
+    // are disabled.
+    let abi_feature_constraints = sess.target.abi_required_features();
+    let abi_incompatible_set =
+        FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
+
+    // Compute implied features
+    let mut all_rust_features = vec![];
+    for feature in sess.opts.cg.target_feature.split(',') {
+        if let Some(feature) = feature.strip_prefix('+') {
+            all_rust_features.extend(
+                UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
+                    .to_sorted_stable_ord()
+                    .iter()
+                    .map(|&&s| (true, s)),
+            )
+        } else if let Some(feature) = feature.strip_prefix('-') {
+            // FIXME: Why do we not remove implied features on "-" here?
+            // We do the equivalent above in `target_features_cfg`.
+            // See <https://github.com/rust-lang/rust/issues/134792>.
+            all_rust_features.push((false, feature));
+        } else if !feature.is_empty() {
             if diagnostics {
-                let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
-                match feature_state {
-                    None => {
-                        let rust_feature =
-                            known_features.iter().find_map(|&(rust_feature, _, _)| {
-                                let gcc_features = to_gcc_features(sess, rust_feature);
-                                if gcc_features.contains(&feature)
-                                    && !gcc_features.contains(&rust_feature)
-                                {
-                                    Some(rust_feature)
-                                } else {
-                                    None
-                                }
-                            });
-                        let unknown_feature = if let Some(rust_feature) = rust_feature {
-                            UnknownCTargetFeature {
-                                feature,
-                                rust_feature: PossibleFeature::Some { rust_feature },
-                            }
-                        } else {
-                            UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
-                        };
-                        sess.dcx().emit_warn(unknown_feature);
-                    }
-                    Some((_, stability, _)) => {
-                        if let Err(reason) =
-                            stability.toggle_allowed(&sess.target, enable_disable == '+')
+                sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
+            }
+        }
+    }
+    // Remove features that are meant for rustc, not codegen.
+    all_rust_features.retain(|(_, feature)| {
+        // Retain if it is not a rustc feature
+        !RUSTC_SPECIFIC_FEATURES.contains(feature)
+    });
+
+    // Check feature validity.
+    if diagnostics {
+        for &(enable, feature) in &all_rust_features {
+            let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
+            match feature_state {
+                None => {
+                    let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| {
+                        let gcc_features = to_gcc_features(sess, rust_feature);
+                        if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature)
                         {
-                            sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
-                        } else if stability.requires_nightly().is_some() {
-                            // An unstable feature. Warn about using it. (It makes little sense
-                            // to hard-error here since we just warn about fully unknown
-                            // features above).
-                            sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+                            Some(rust_feature)
+                        } else {
+                            None
                         }
+                    });
+                    let unknown_feature = if let Some(rust_feature) = rust_feature {
+                        UnknownCTargetFeature {
+                            feature,
+                            rust_feature: PossibleFeature::Some { rust_feature },
+                        }
+                    } else {
+                        UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                    };
+                    sess.dcx().emit_warn(unknown_feature);
+                }
+                Some((_, stability, _)) => {
+                    if let Err(reason) = stability.toggle_allowed() {
+                        sess.dcx().emit_warn(ForbiddenCTargetFeature {
+                            feature,
+                            enabled: if enable { "enabled" } else { "disabled" },
+                            reason,
+                        });
+                    } else if stability.requires_nightly().is_some() {
+                        // An unstable feature. Warn about using it. (It makes little sense
+                        // to hard-error here since we just warn about fully unknown
+                        // features above).
+                        sess.dcx().emit_warn(UnstableCTargetFeature { feature });
                     }
                 }
+            }
 
-                // FIXME(nagisa): figure out how to not allocate a full hashset here.
-                featsmap.insert(feature, enable_disable == '+');
+            // Ensure that the features we enable/disable are compatible with the ABI.
+            if enable {
+                if abi_incompatible_set.contains(feature) {
+                    sess.dcx().emit_warn(ForbiddenCTargetFeature {
+                        feature,
+                        enabled: "enabled",
+                        reason: "this feature is incompatible with the target ABI",
+                    });
+                }
+            } else {
+                // FIXME: we have to request implied features here since
+                // negative features do not handle implied features above.
+                for &required in abi_feature_constraints.required.iter() {
+                    let implied = sess.target.implied_target_features(std::iter::once(required));
+                    if implied.contains(feature) {
+                        sess.dcx().emit_warn(ForbiddenCTargetFeature {
+                            feature,
+                            enabled: "disabled",
+                            reason: "this feature is required by the target ABI",
+                        });
+                    }
+                }
             }
 
-            // ... otherwise though we run through `to_gcc_features` when
+            // FIXME(nagisa): figure out how to not allocate a full hashset here.
+            featsmap.insert(feature, enable);
+        }
+    }
+
+    // To be sure the ABI-relevant features are all in the right state, we explicitly
+    // (un)set them here. This means if the target spec sets those features wrong,
+    // we will silently correct them rather than silently producing wrong code.
+    // (The target sanity check tries to catch this, but we can't know which features are
+    // enabled in GCC by default so we can't be fully sure about that check.)
+    // We add these at the beginning of the list so that `-Ctarget-features` can
+    // still override it... that's unsound, but more compatible with past behavior.
+    all_rust_features.splice(
+        0..0,
+        abi_feature_constraints
+            .required
+            .iter()
+            .map(|&f| (true, f))
+            .chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
+    );
+
+    // Translate this into GCC features.
+    let feats = all_rust_features
+        .iter()
+        .filter_map(|&(enable, feature)| {
+            let enable_disable = if enable { '+' } else { '-' };
+            // We run through `to_gcc_features` when
             // passing requests down to GCC. This means that all in-language
             // features also work on the command line instead of having two
             // different names when the GCC name and the Rust name differ.
@@ -146,26 +203,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     features
 }
 
-/// Returns a feature name for the given `+feature` or `-feature` string.
-///
-/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
-fn backend_feature_name(s: &str) -> Option<&str> {
-    // features must start with a `+` or `-`.
-    let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| {
-        bug!("target feature `{}` must begin with a `+` or `-`", s);
-    });
-    // Rustc-specific feature requests like `+crt-static` or `-crt-static`
-    // are not passed down to GCC.
-    if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-        return None;
-    }
-    Some(feature)
-}
-
 // To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
 pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
     let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
     match (arch, s) {
+        // FIXME: seems like x87 does not exist?
+        ("x86", "x87") => smallvec![],
         ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"],
         ("x86", "pclmulqdq") => smallvec!["pclmul"],
         ("x86", "rdrand") => smallvec!["rdrnd"],
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 689986d642d..c44d1a5e5c2 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -9,6 +9,7 @@ test = false
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+gimli = "0.30"
 itertools = "0.12"
 libc = "0.2"
 measureme = "11"
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index 3982c37528d..9585848cbf0 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -10,7 +10,7 @@ codegen_llvm_dynamic_linking_with_lto =
 codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
 
 codegen_llvm_forbidden_ctarget_feature =
-    target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
+    target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
     .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
 
@@ -24,8 +24,6 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two =
 codegen_llvm_invalid_minimum_alignment_too_large =
     invalid minimum global alignment: {$align} is too large
 
-codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`"
-
 codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
 codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
new file mode 100644
index 00000000000..40842915222
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
@@ -0,0 +1,37 @@
+//! Definitions of various DWARF-related constants.
+
+use libc::c_uint;
+
+/// Helper macro to let us redeclare gimli's constants as our own constants
+/// with a different type, with less risk of copy-paste errors.
+macro_rules! declare_constant {
+    (
+        $name:ident : $type:ty
+    ) => {
+        #[allow(non_upper_case_globals)]
+        pub(crate) const $name: $type = ::gimli::constants::$name.0 as $type;
+
+        // Assert that as-cast probably hasn't changed the value.
+        const _: () = assert!($name as i128 == ::gimli::constants::$name.0 as i128);
+    };
+}
+
+declare_constant!(DW_TAG_const_type: c_uint);
+
+// DWARF languages.
+declare_constant!(DW_LANG_Rust: c_uint);
+
+// DWARF attribute type encodings.
+declare_constant!(DW_ATE_boolean: c_uint);
+declare_constant!(DW_ATE_float: c_uint);
+declare_constant!(DW_ATE_signed: c_uint);
+declare_constant!(DW_ATE_unsigned: c_uint);
+declare_constant!(DW_ATE_UTF: c_uint);
+
+// DWARF expression operators.
+declare_constant!(DW_OP_deref: u64);
+declare_constant!(DW_OP_plus_uconst: u64);
+/// Defined by LLVM in `llvm/include/llvm/BinaryFormat/Dwarf.h`.
+/// Double-checked by a static assertion in `RustWrapper.cpp`.
+#[allow(non_upper_case_globals)]
+pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 40248a9009a..88e43e1c678 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -22,6 +22,7 @@ use rustc_target::spec::DebuginfoKind;
 use smallvec::smallvec;
 use tracing::{debug, instrument};
 
+pub(crate) use self::type_map::TypeMap;
 use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId};
 use super::CodegenUnitDebugContext;
 use super::namespace::mangled_name_of_instance;
@@ -30,6 +31,7 @@ use super::utils::{
     DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit,
 };
 use crate::common::{AsCCharPtr, CodegenCx};
+use crate::debuginfo::dwarf_const;
 use crate::debuginfo::metadata::type_map::build_type_with_children;
 use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
 use crate::llvm::debuginfo::{
@@ -59,20 +61,6 @@ impl fmt::Debug for llvm::Metadata {
     }
 }
 
-// From DWARF 5.
-// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1.
-const DW_LANG_RUST: c_uint = 0x1c;
-#[allow(non_upper_case_globals)]
-const DW_ATE_boolean: c_uint = 0x02;
-#[allow(non_upper_case_globals)]
-const DW_ATE_float: c_uint = 0x04;
-#[allow(non_upper_case_globals)]
-const DW_ATE_signed: c_uint = 0x05;
-#[allow(non_upper_case_globals)]
-const DW_ATE_unsigned: c_uint = 0x07;
-#[allow(non_upper_case_globals)]
-const DW_ATE_UTF: c_uint = 0x10;
-
 pub(super) const UNKNOWN_LINE_NUMBER: c_uint = 0;
 pub(super) const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
 
@@ -87,8 +75,6 @@ type SmallVec<T> = smallvec::SmallVec<[T; 16]>;
 mod enums;
 mod type_map;
 
-pub(crate) use type_map::TypeMap;
-
 /// Returns from the enclosing function if the type debuginfo node with the given
 /// unique ID can be found in the type map.
 macro_rules! return_if_di_node_created_in_meantime {
@@ -519,7 +505,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D
                 name.as_c_char_ptr(),
                 name.len(),
                 cx.tcx.data_layout.pointer_size.bits(),
-                DW_ATE_unsigned,
+                dwarf_const::DW_ATE_unsigned,
             )
         }
     })
@@ -778,6 +764,8 @@ fn build_basic_type_di_node<'ll, 'tcx>(
     // .natvis visualizers (and perhaps other existing native debuggers?)
     let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
 
+    use dwarf_const::{DW_ATE_UTF, DW_ATE_boolean, DW_ATE_float, DW_ATE_signed, DW_ATE_unsigned};
+
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
         ty::Tuple(elements) if elements.is_empty() => {
@@ -958,7 +946,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
 
         let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
             debug_context.builder,
-            DW_LANG_RUST,
+            dwarf_const::DW_LANG_Rust,
             compile_unit_file,
             producer.as_c_char_ptr(),
             producer.len(),
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index 23e11748e52..a72e205c9b2 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
 use smallvec::smallvec;
 
 use crate::common::{AsCCharPtr, CodegenCx};
+use crate::debuginfo::dwarf_const::DW_TAG_const_type;
 use crate::debuginfo::metadata::enums::DiscrResult;
 use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
 use crate::debuginfo::metadata::{
@@ -566,22 +567,39 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
                 None,
             ));
 
-            let build_assoc_const =
-                |name: &str, type_di_node: &'ll DIType, value: u64, align: Align| unsafe {
-                    llvm::LLVMRustDIBuilderCreateStaticMemberType(
-                        DIB(cx),
-                        wrapper_struct_type_di_node,
-                        name.as_c_char_ptr(),
-                        name.len(),
-                        unknown_file_metadata(cx),
-                        UNKNOWN_LINE_NUMBER,
-                        type_di_node,
-                        DIFlags::FlagZero,
-                        Some(cx.const_u64(value)),
-                        align.bits() as u32,
-                    )
+            let build_assoc_const = |name: &str,
+                                     type_di_node_: &'ll DIType,
+                                     value: u64,
+                                     align: Align| unsafe {
+                // FIXME: Currently we force all DISCR_* values to be u64's as LLDB seems to have
+                // problems inspecting other value types. Since DISCR_* is typically only going to be
+                // directly inspected via the debugger visualizer - which compares it to the `tag` value
+                // (whose type is not modified at all) it shouldn't cause any real problems.
+                let (t_di, align) = if name == ASSOC_CONST_DISCR_NAME {
+                    (type_di_node_, align.bits() as u32)
+                } else {
+                    let ty_u64 = Ty::new_uint(cx.tcx, ty::UintTy::U64);
+                    (type_di_node(cx, ty_u64), Align::EIGHT.bits() as u32)
                 };
 
+                // must wrap type in a `const` modifier for LLDB to be able to inspect the value of the member
+                let field_type =
+                    llvm::LLVMRustDIBuilderCreateQualifiedType(DIB(cx), DW_TAG_const_type, t_di);
+
+                llvm::LLVMRustDIBuilderCreateStaticMemberType(
+                    DIB(cx),
+                    wrapper_struct_type_di_node,
+                    name.as_c_char_ptr(),
+                    name.len(),
+                    unknown_file_metadata(cx),
+                    UNKNOWN_LINE_NUMBER,
+                    field_type,
+                    DIFlags::FlagZero,
+                    Some(cx.const_u64(value)),
+                    align,
+                )
+            };
+
             // We also always have an associated constant for the discriminant value
             // of the variant.
             fields.push(build_assoc_const(
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index fae698bea2a..755f4816acf 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -39,6 +39,7 @@ use crate::llvm::debuginfo::{
 use crate::value::Value;
 
 mod create_scope_map;
+mod dwarf_const;
 mod gdb;
 pub(crate) mod metadata;
 mod namespace;
@@ -47,6 +48,10 @@ mod utils;
 use self::create_scope_map::compute_mir_scopes;
 pub(crate) use self::metadata::build_global_var_di_node;
 
+// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were
+// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp`
+// to decide which C++ API to call. Instead, we should just have two separate
+// FFI functions and choose the correct one on the Rust side.
 #[allow(non_upper_case_globals)]
 const DW_TAG_auto_variable: c_uint = 0x100;
 #[allow(non_upper_case_globals)]
@@ -152,29 +157,26 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
         indirect_offsets: &[Size],
         fragment: Option<Range<Size>>,
     ) {
+        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
+
         // Convert the direct and indirect offsets and fragment byte range to address ops.
-        // FIXME(eddyb) use `const`s instead of getting the values via FFI,
-        // the values should match the ones in the DWARF standard anyway.
-        let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
-        let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
-        let op_llvm_fragment = || unsafe { llvm::LLVMRustDIBuilderCreateOpLLVMFragment() };
         let mut addr_ops = SmallVec::<[u64; 8]>::new();
 
         if direct_offset.bytes() > 0 {
-            addr_ops.push(op_plus_uconst());
+            addr_ops.push(DW_OP_plus_uconst);
             addr_ops.push(direct_offset.bytes() as u64);
         }
         for &offset in indirect_offsets {
-            addr_ops.push(op_deref());
+            addr_ops.push(DW_OP_deref);
             if offset.bytes() > 0 {
-                addr_ops.push(op_plus_uconst());
+                addr_ops.push(DW_OP_plus_uconst);
                 addr_ops.push(offset.bytes() as u64);
             }
         }
         if let Some(fragment) = fragment {
             // `DW_OP_LLVM_fragment` takes as arguments the fragment's
             // offset and size, both of them in bits.
-            addr_ops.push(op_llvm_fragment());
+            addr_ops.push(DW_OP_LLVM_fragment);
             addr_ops.push(fragment.start.bits() as u64);
             addr_ops.push((fragment.end - fragment.start).bits() as u64);
         }
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index f340b06e876..f4c9491f758 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -37,6 +37,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
 #[note(codegen_llvm_forbidden_ctarget_feature_issue)]
 pub(crate) struct ForbiddenCTargetFeature<'a> {
     pub feature: &'a str,
+    pub enabled: &'a str,
     pub reason: &'a str,
 }
 
@@ -214,12 +215,6 @@ pub(crate) struct MismatchedDataLayout<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_llvm_invalid_target_feature_prefix)]
-pub(crate) struct InvalidTargetFeaturePrefix<'a> {
-    pub feature: &'a str,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_llvm_fixed_x18_invalid_arch)]
 pub(crate) struct FixedX18InvalidArch<'a> {
     pub arch: &'a str,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 472d4a3a72b..bb324ee682c 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2008,6 +2008,12 @@ unsafe extern "C" {
         AlignInBits: u32,
     ) -> &'a DIDerivedType;
 
+    pub fn LLVMRustDIBuilderCreateQualifiedType<'a>(
+        Builder: &DIBuilder<'a>,
+        Tag: c_uint,
+        Type: &'a DIType,
+    ) -> &'a DIDerivedType;
+
     pub fn LLVMRustDIBuilderCreateLexicalBlock<'a>(
         Builder: &DIBuilder<'a>,
         Scope: &'a DIScope,
@@ -2171,9 +2177,6 @@ unsafe extern "C" {
         Location: &'a DILocation,
         BD: c_uint,
     ) -> Option<&'a DILocation>;
-    pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
-    pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
-    pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
 
     pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
     pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 628c0b1c29c..e18e91e569f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -21,8 +21,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU
 
 use crate::back::write::create_informational_target_machine;
 use crate::errors::{
-    FixedX18InvalidArch, ForbiddenCTargetFeature, InvalidTargetFeaturePrefix, PossibleFeature,
-    UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
+    FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
+    UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
 };
 use crate::llvm;
 
@@ -348,7 +348,16 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
     {
         if enabled {
             // Also add all transitively implied features.
-            features.extend(sess.target.implied_target_features(std::iter::once(feature)));
+
+            // We don't care about the order in `features` since the only thing we use it for is the
+            // `features.contains` below.
+            #[allow(rustc::potential_query_instability)]
+            features.extend(
+                sess.target
+                    .implied_target_features(std::iter::once(feature.as_str()))
+                    .iter()
+                    .map(|s| Symbol::intern(s)),
+            );
         } else {
             // Remove transitively reverse-implied features.
 
@@ -356,7 +365,11 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
             // `features.contains` below.
             #[allow(rustc::potential_query_instability)]
             features.retain(|f| {
-                if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) {
+                if sess
+                    .target
+                    .implied_target_features(std::iter::once(f.as_str()))
+                    .contains(&feature.as_str())
+                {
                     // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
                     // remove `f`. (This is the standard logical contraposition principle.)
                     false
@@ -638,7 +651,7 @@ pub(crate) fn global_llvm_features(
         sess.target
             .features
             .split(',')
-            .filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
+            .filter(|v| !v.is_empty())
             // Drop +v8plus feature introduced in LLVM 20.
             .filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
             .map(String::from),
@@ -651,89 +664,136 @@ pub(crate) fn global_llvm_features(
     // -Ctarget-features
     if !only_base_features {
         let known_features = sess.target.rust_target_features();
+        // Will only be filled when `diagnostics` is set!
         let mut featsmap = FxHashMap::default();
 
-        // insert implied features
+        // Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
+        // are disabled.
+        let abi_feature_constraints = sess.target.abi_required_features();
+        let abi_incompatible_set =
+            FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
+
+        // Compute implied features
         let mut all_rust_features = vec![];
         for feature in sess.opts.cg.target_feature.split(',') {
-            match feature.strip_prefix('+') {
-                Some(feature) => all_rust_features.extend(
-                    UnordSet::from(
-                        sess.target
-                            .implied_target_features(std::iter::once(Symbol::intern(feature))),
-                    )
-                    .to_sorted_stable_ord()
-                    .iter()
-                    .map(|s| format!("+{}", s.as_str())),
-                ),
-                _ => all_rust_features.push(feature.to_string()),
+            if let Some(feature) = feature.strip_prefix('+') {
+                all_rust_features.extend(
+                    UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
+                        .to_sorted_stable_ord()
+                        .iter()
+                        .map(|&&s| (true, s)),
+                )
+            } else if let Some(feature) = feature.strip_prefix('-') {
+                // FIXME: Why do we not remove implied features on "-" here?
+                // We do the equivalent above in `target_features_cfg`.
+                // See <https://github.com/rust-lang/rust/issues/134792>.
+                all_rust_features.push((false, feature));
+            } else if !feature.is_empty() {
+                if diagnostics {
+                    sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
+                }
             }
         }
+        // Remove features that are meant for rustc, not LLVM.
+        all_rust_features.retain(|(_, feature)| {
+            // Retain if it is not a rustc feature
+            !RUSTC_SPECIFIC_FEATURES.contains(feature)
+        });
 
-        let feats = all_rust_features
-            .iter()
-            .filter_map(|s| {
-                let enable_disable = match s.chars().next() {
-                    None => return None,
-                    Some(c @ ('+' | '-')) => c,
-                    Some(_) => {
-                        if diagnostics {
-                            sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
-                        }
-                        return None;
-                    }
-                };
-
-                // Get the backend feature name, if any.
-                // This excludes rustc-specific features, which do not get passed to LLVM.
-                let feature = backend_feature_name(sess, s)?;
-                // Warn against use of LLVM specific feature names and unstable features on the CLI.
-                if diagnostics {
-                    let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
-                    match feature_state {
-                        None => {
-                            let rust_feature =
-                                known_features.iter().find_map(|&(rust_feature, _, _)| {
-                                    let llvm_features = to_llvm_features(sess, rust_feature)?;
-                                    if llvm_features.contains(feature)
-                                        && !llvm_features.contains(rust_feature)
-                                    {
-                                        Some(rust_feature)
-                                    } else {
-                                        None
-                                    }
-                                });
-                            let unknown_feature = if let Some(rust_feature) = rust_feature {
-                                UnknownCTargetFeature {
-                                    feature,
-                                    rust_feature: PossibleFeature::Some { rust_feature },
+        // Check feature validity.
+        if diagnostics {
+            for &(enable, feature) in &all_rust_features {
+                let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
+                match feature_state {
+                    None => {
+                        let rust_feature =
+                            known_features.iter().find_map(|&(rust_feature, _, _)| {
+                                let llvm_features = to_llvm_features(sess, rust_feature)?;
+                                if llvm_features.contains(feature)
+                                    && !llvm_features.contains(rust_feature)
+                                {
+                                    Some(rust_feature)
+                                } else {
+                                    None
                                 }
-                            } else {
-                                UnknownCTargetFeature {
-                                    feature,
-                                    rust_feature: PossibleFeature::None,
-                                }
-                            };
-                            sess.dcx().emit_warn(unknown_feature);
-                        }
-                        Some((_, stability, _)) => {
-                            if let Err(reason) =
-                                stability.toggle_allowed(&sess.target, enable_disable == '+')
-                            {
-                                sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
-                            } else if stability.requires_nightly().is_some() {
-                                // An unstable feature. Warn about using it. It makes little sense
-                                // to hard-error here since we just warn about fully unknown
-                                // features above.
-                                sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+                            });
+                        let unknown_feature = if let Some(rust_feature) = rust_feature {
+                            UnknownCTargetFeature {
+                                feature,
+                                rust_feature: PossibleFeature::Some { rust_feature },
                             }
+                        } else {
+                            UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
+                        };
+                        sess.dcx().emit_warn(unknown_feature);
+                    }
+                    Some((_, stability, _)) => {
+                        if let Err(reason) = stability.toggle_allowed() {
+                            sess.dcx().emit_warn(ForbiddenCTargetFeature {
+                                feature,
+                                enabled: if enable { "enabled" } else { "disabled" },
+                                reason,
+                            });
+                        } else if stability.requires_nightly().is_some() {
+                            // An unstable feature. Warn about using it. It makes little sense
+                            // to hard-error here since we just warn about fully unknown
+                            // features above.
+                            sess.dcx().emit_warn(UnstableCTargetFeature { feature });
                         }
                     }
+                }
 
-                    // FIXME(nagisa): figure out how to not allocate a full hashset here.
-                    featsmap.insert(feature, enable_disable == '+');
+                // Ensure that the features we enable/disable are compatible with the ABI.
+                if enable {
+                    if abi_incompatible_set.contains(feature) {
+                        sess.dcx().emit_warn(ForbiddenCTargetFeature {
+                            feature,
+                            enabled: "enabled",
+                            reason: "this feature is incompatible with the target ABI",
+                        });
+                    }
+                } else {
+                    // FIXME: we have to request implied features here since
+                    // negative features do not handle implied features above.
+                    for &required in abi_feature_constraints.required.iter() {
+                        let implied =
+                            sess.target.implied_target_features(std::iter::once(required));
+                        if implied.contains(feature) {
+                            sess.dcx().emit_warn(ForbiddenCTargetFeature {
+                                feature,
+                                enabled: "disabled",
+                                reason: "this feature is required by the target ABI",
+                            });
+                        }
+                    }
                 }
 
+                // FIXME(nagisa): figure out how to not allocate a full hashset here.
+                featsmap.insert(feature, enable);
+            }
+        }
+
+        // To be sure the ABI-relevant features are all in the right state, we explicitly
+        // (un)set them here. This means if the target spec sets those features wrong,
+        // we will silently correct them rather than silently producing wrong code.
+        // (The target sanity check tries to catch this, but we can't know which features are
+        // enabled in LLVM by default so we can't be fully sure about that check.)
+        // We add these at the beginning of the list so that `-Ctarget-features` can
+        // still override it... that's unsound, but more compatible with past behavior.
+        all_rust_features.splice(
+            0..0,
+            abi_feature_constraints
+                .required
+                .iter()
+                .map(|&f| (true, f))
+                .chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
+        );
+
+        // Translate this into LLVM features.
+        let feats = all_rust_features
+            .iter()
+            .filter_map(|&(enable, feature)| {
+                let enable_disable = if enable { '+' } else { '-' };
                 // We run through `to_llvm_features` when
                 // passing requests down to LLVM. This means that all in-language
                 // features also work on the command line instead of having two
@@ -746,9 +806,9 @@ pub(crate) fn global_llvm_features(
                         enable_disable, llvm_feature.llvm_feature_name
                     ))
                     .chain(llvm_feature.dependency.into_iter().filter_map(
-                        move |feat| match (enable_disable, feat) {
-                            ('-' | '+', TargetFeatureFoldStrength::Both(f))
-                            | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
+                        move |feat| match (enable, feat) {
+                            (_, TargetFeatureFoldStrength::Both(f))
+                            | (true, TargetFeatureFoldStrength::EnableOnly(f)) => {
                                 Some(format!("{enable_disable}{f}"))
                             }
                             _ => None,
@@ -780,22 +840,6 @@ pub(crate) fn global_llvm_features(
     features
 }
 
-/// Returns a feature name for the given `+feature` or `-feature` string.
-///
-/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
-fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
-    // features must start with a `+` or `-`.
-    let feature = s
-        .strip_prefix(&['+', '-'][..])
-        .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
-    // Rustc-specific feature requests like `+crt-static` or `-crt-static`
-    // are not passed down to LLVM.
-    if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-        return None;
-    }
-    Some(feature)
-}
-
 pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> {
     let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
     Some(handle_native(name))
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 56188714b44..484f467068a 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -67,7 +67,7 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
 codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
 
 codegen_ssa_forbidden_target_feature_attr =
-    target feature `{$feature}` cannot be toggled with `#[target_feature]`: {$reason}
+    target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason}
 
 codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
 
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 7e80d014ea2..d8b9bdb55da 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -19,7 +19,7 @@ use crate::errors;
 pub(crate) fn from_target_feature_attr(
     tcx: TyCtxt<'_>,
     attr: &hir::Attribute,
-    rust_target_features: &UnordMap<String, target_features::StabilityComputed>,
+    rust_target_features: &UnordMap<String, target_features::Stability>,
     target_features: &mut Vec<TargetFeature>,
 ) {
     let Some(list) = attr.meta_item_list() else { return };
@@ -32,7 +32,7 @@ pub(crate) fn from_target_feature_attr(
             .emit();
     };
     let rust_features = tcx.features();
-    let mut added_target_features = Vec::new();
+    let abi_feature_constraints = tcx.sess.target.abi_required_features();
     for item in list {
         // Only `enable = ...` is accepted in the meta-item list.
         if !item.has_name(sym::enable) {
@@ -47,7 +47,7 @@ pub(crate) fn from_target_feature_attr(
         };
 
         // We allow comma separation to enable multiple features.
-        added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
+        for feature in value.as_str().split(',') {
             let Some(stability) = rust_target_features.get(feature) else {
                 let msg = format!("the feature named `{feature}` is not valid for this target");
                 let mut err = tcx.dcx().struct_span_err(item.span(), msg);
@@ -59,12 +59,12 @@ pub(crate) fn from_target_feature_attr(
                     }
                 }
                 err.emit();
-                return None;
+                continue;
             };
 
             // Only allow target features whose feature gates have been enabled
             // and which are permitted to be toggled.
-            if let Err(reason) = stability.toggle_allowed(/*enable*/ true) {
+            if let Err(reason) = stability.toggle_allowed() {
                 tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
                     span: item.span(),
                     feature,
@@ -80,31 +80,25 @@ pub(crate) fn from_target_feature_attr(
                     format!("the target feature `{feature}` is currently unstable"),
                 )
                 .emit();
+            } else {
+                // Add this and the implied features.
+                let feature_sym = Symbol::intern(feature);
+                for &name in tcx.implied_target_features(feature_sym) {
+                    // But ensure the ABI does not forbid enabling this.
+                    // Here we do assume that LLVM doesn't add even more implied features
+                    // we don't know about, at least no features that would have ABI effects!
+                    if abi_feature_constraints.incompatible.contains(&name.as_str()) {
+                        tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
+                            span: item.span(),
+                            feature: name.as_str(),
+                            reason: "this feature is incompatible with the target ABI",
+                        });
+                    }
+                    target_features.push(TargetFeature { name, implied: name != feature_sym })
+                }
             }
-            Some(Symbol::intern(feature))
-        }));
-    }
-
-    // Add explicit features
-    target_features.extend(
-        added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
-    );
-
-    // Add implied features
-    let mut implied_target_features = UnordSet::new();
-    for feature in added_target_features.iter() {
-        implied_target_features.extend(tcx.implied_target_features(*feature).clone());
-    }
-    for feature in added_target_features.iter() {
-        implied_target_features.remove(feature);
+        }
     }
-    target_features.extend(
-        implied_target_features
-            .into_sorted_stable_ord()
-            .iter()
-            .copied()
-            .map(|name| TargetFeature { name, implied: true }),
-    )
 }
 
 /// Computes the set of target features used in a function for the purposes of
@@ -147,25 +141,28 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         rust_target_features: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
-            let target = &tcx.sess.target;
             if tcx.sess.opts.actually_rustdoc {
                 // rustdoc needs to be able to document functions that use all the features, so
                 // whitelist them all
                 rustc_target::target_features::all_rust_features()
-                    .map(|(a, b)| (a.to_string(), b.compute_toggleability(target)))
+                    .map(|(a, b)| (a.to_string(), b))
                     .collect()
             } else {
                 tcx.sess
                     .target
                     .rust_target_features()
                     .iter()
-                    .map(|(a, b, _)| (a.to_string(), b.compute_toggleability(target)))
+                    .map(|(a, b, _)| (a.to_string(), *b))
                     .collect()
             }
         },
-        implied_target_features: |tcx, feature| {
+        implied_target_features: |tcx, feature: Symbol| {
+            let feature = feature.as_str();
             UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
                 .into_sorted_stable_ord()
+                .into_iter()
+                .map(|s| Symbol::intern(s))
+                .collect()
         },
         asm_target_features,
         ..*providers
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 489ef5e8fe7..00bb4d65579 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -933,11 +933,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
          the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
     ),
-    rustc_attr!(
-        rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
-        "#[rustc_box] allows creating boxes \
-        and it is only intended to be used in `alloc`."
-    ),
 
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 747431e5312..8aa95d1c1d5 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -86,6 +86,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::assert_inhabited
         | sym::assert_zero_valid
         | sym::assert_mem_uninitialized_valid
+        | sym::box_new
         | sym::breakpoint
         | sym::size_of
         | sym::min_align_of
@@ -606,6 +607,8 @@ pub fn check_intrinsic_type(
 
             sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool),
 
+            sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))),
+
             sym::simd_eq
             | sym::simd_ne
             | sym::simd_lt
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 87b1c944aa8..dd72ea2497f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -54,6 +54,10 @@ using namespace llvm;
 using namespace llvm::sys;
 using namespace llvm::object;
 
+// This opcode is an LLVM detail that could hypothetically change (?), so
+// verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM.
+static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000);
+
 // LLVMAtomicOrdering is already an enum - don't create another
 // one.
 static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
@@ -1218,6 +1222,13 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType(
 }
 
 extern "C" LLVMMetadataRef
+LLVMRustDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag,
+                                     LLVMMetadataRef Type) {
+  return wrap(
+      unwrap(Builder)->createQualifiedType(Tag, unwrapDI<DIType>(Type)));
+}
+
+extern "C" LLVMMetadataRef
 LLVMRustDIBuilderCreateLexicalBlock(LLVMRustDIBuilderRef Builder,
                                     LLVMMetadataRef Scope, LLVMMetadataRef File,
                                     unsigned Line, unsigned Col) {
@@ -1390,18 +1401,6 @@ LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location,
   return wrap(NewLoc.has_value() ? NewLoc.value() : nullptr);
 }
 
-extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
-  return dwarf::DW_OP_deref;
-}
-
-extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
-  return dwarf::DW_OP_plus_uconst;
-}
-
-extern "C" uint64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
-  return dwarf::DW_OP_LLVM_fragment;
-}
-
 extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) {
   auto OS = RawRustStringOstream(Str);
   unwrap<llvm::Type>(Ty)->print(OS);
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 241767fe249..16d868300db 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -28,6 +28,7 @@ pub struct CodegenFnAttrs {
     pub link_ordinal: Option<u16>,
     /// The `#[target_feature(enable = "...")]` attribute and the enabled
     /// features (only enabled features are supported right now).
+    /// Implied target features have already been applied.
     pub target_features: Vec<TargetFeature>,
     /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
     pub linkage: Option<Linkage>,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c960f03cf06..95995b956cd 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2357,7 +2357,7 @@ rustc_queries! {
     }
 
     /// Returns the Rust target features for the current target. These are not always the same as LLVM target features!
-    query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::StabilityComputed> {
+    query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::Stability> {
         arena_cache
         eval_always
         desc { "looking up Rust target features" }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index edba247c7b0..5d61a9d1e75 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -287,11 +287,6 @@ mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabite
 
 mir_build_rust_2024_incompatible_pat = this pattern relies on behavior which may change in edition 2024
 
-mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
-    .attributes = no other attributes may be applied
-    .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
-    .missing_box = `#[rustc_box]` requires the `owned_box` lang item
-
 mir_build_static_in_pattern = statics cannot be referenced in patterns
     .label = can't be used in patterns
 mir_build_static_in_pattern_def = `static` defined here
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index be5f8bdffb5..790d56860d2 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1067,25 +1067,6 @@ pub(crate) enum MiscPatternSuggestion {
     },
 }
 
-#[derive(Diagnostic)]
-#[diag(mir_build_rustc_box_attribute_error)]
-pub(crate) struct RustcBoxAttributeError {
-    #[primary_span]
-    pub(crate) span: Span,
-    #[subdiagnostic]
-    pub(crate) reason: RustcBoxAttrReason,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum RustcBoxAttrReason {
-    #[note(mir_build_attributes)]
-    Attributes,
-    #[note(mir_build_not_box)]
-    NotBoxNew,
-    #[note(mir_build_missing_box)]
-    MissingBox,
-}
-
 #[derive(LintDiagnostic)]
 #[diag(mir_build_rust_2024_incompatible_pat)]
 pub(crate) struct Rust2024IncompatiblePat<'a> {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 0338ac674e5..9cdf08d749b 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -20,7 +20,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, sym};
 use tracing::{debug, info, instrument, trace};
 
-use crate::errors;
 use crate::thir::cx::Cx;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
@@ -380,45 +379,25 @@ impl<'tcx> Cx<'tcx> {
                         from_hir_call: true,
                         fn_span: expr.span,
                     }
-                } else {
-                    let attrs = tcx.hir().attrs(expr.hir_id);
-                    if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_box) {
-                        if attrs.len() != 1 {
-                            tcx.dcx().emit_err(errors::RustcBoxAttributeError {
-                                span: attrs[0].span,
-                                reason: errors::RustcBoxAttrReason::Attributes,
-                            });
-                        } else if let Some(box_item) = tcx.lang_items().owned_box() {
-                            if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) =
-                                fun.kind
-                                && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
-                                && path.res.opt_def_id().is_some_and(|did| did == box_item)
-                                && fn_path.ident.name == sym::new
-                                && let [value] = args
-                            {
-                                return Expr {
-                                    temp_lifetime: TempLifetime {
-                                        temp_lifetime,
-                                        backwards_incompatible,
-                                    },
-                                    ty: expr_ty,
-                                    span: expr.span,
-                                    kind: ExprKind::Box { value: self.mirror_expr(value) },
-                                };
-                            } else {
-                                tcx.dcx().emit_err(errors::RustcBoxAttributeError {
-                                    span: expr.span,
-                                    reason: errors::RustcBoxAttrReason::NotBoxNew,
-                                });
-                            }
-                        } else {
-                            tcx.dcx().emit_err(errors::RustcBoxAttributeError {
-                                span: attrs[0].span,
-                                reason: errors::RustcBoxAttrReason::MissingBox,
-                            });
-                        }
+                } else if let ty::FnDef(def_id, _) = self.typeck_results().expr_ty(fun).kind()
+                    && let Some(intrinsic) = self.tcx.intrinsic(def_id)
+                    && intrinsic.name == sym::box_new
+                {
+                    // We don't actually evaluate `fun` here, so make sure that doesn't miss any side-effects.
+                    if !matches!(fun.kind, hir::ExprKind::Path(_)) {
+                        span_bug!(
+                            expr.span,
+                            "`box_new` intrinsic can only be called via path expression"
+                        );
                     }
-
+                    let value = &args[0];
+                    return Expr {
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                        ty: expr_ty,
+                        span: expr.span,
+                        kind: ExprKind::Box { value: self.mirror_expr(value) },
+                    };
+                } else {
                     // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
                     let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind
                         && let Some(adt_def) = expr_ty.ty_adt_def()
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 4ecc4201f89..bdfbfb1e38d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1696,7 +1696,6 @@ symbols! {
         rustc_as_ptr,
         rustc_attrs,
         rustc_autodiff,
-        rustc_box,
         rustc_builtin_macro,
         rustc_capture_analysis,
         rustc_clean,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 02962d55a60..ddfa6e248c3 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1926,6 +1926,8 @@ supported_targets! {
     ("mipsel-sony-psp", mipsel_sony_psp),
     ("mipsel-sony-psx", mipsel_sony_psx),
     ("mipsel-unknown-none", mipsel_unknown_none),
+    ("mips-mti-none-elf", mips_mti_none_elf),
+    ("mipsel-mti-none-elf", mipsel_mti_none_elf),
     ("thumbv4t-none-eabi", thumbv4t_none_eabi),
     ("armv4t-none-eabi", armv4t_none_eabi),
     ("thumbv5te-none-eabi", thumbv5te_none_eabi),
@@ -2651,10 +2653,6 @@ impl TargetOptions {
     pub(crate) fn has_feature(&self, search_feature: &str) -> bool {
         self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature))
     }
-
-    pub(crate) fn has_neg_feature(&self, search_feature: &str) -> bool {
-        self.features.split(',').any(|f| f.strip_prefix('-').is_some_and(|f| f == search_feature))
-    }
 }
 
 impl Default for TargetOptions {
@@ -3201,7 +3199,8 @@ impl Target {
                 check_matches!(
                     &*self.llvm_abiname,
                     "ilp32" | "ilp32f" | "ilp32d" | "ilp32e",
-                    "invalid RISC-V ABI name"
+                    "invalid RISC-V ABI name: {}",
+                    self.llvm_abiname,
                 );
             }
             "riscv64" => {
@@ -3209,7 +3208,8 @@ impl Target {
                 check_matches!(
                     &*self.llvm_abiname,
                     "lp64" | "lp64f" | "lp64d" | "lp64e",
-                    "invalid RISC-V ABI name"
+                    "invalid RISC-V ABI name: {}",
+                    self.llvm_abiname,
                 );
             }
             "arm" => {
@@ -3243,6 +3243,26 @@ impl Target {
                     ));
                 }
             }
+            // Check that we don't mis-set any of the ABI-relevant features.
+            let abi_feature_constraints = self.abi_required_features();
+            for feat in abi_feature_constraints.required {
+                // The feature might be enabled by default so we can't *require* it to show up.
+                // But it must not be *disabled*.
+                if features_disabled.contains(feat) {
+                    return Err(format!(
+                        "target feature `{feat}` is required by the ABI but gets disabled in target spec"
+                    ));
+                }
+            }
+            for feat in abi_feature_constraints.incompatible {
+                // The feature might be disabled by default so we can't *require* it to show up.
+                // But it must not be *enabled*.
+                if features_enabled.contains(feat) {
+                    return Err(format!(
+                        "target feature `{feat}` is incompatible with the ABI but gets enabled in target spec"
+                    ));
+                }
+            }
         }
 
         Ok(())
diff --git a/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs
new file mode 100644
index 00000000000..4637e31fb17
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/mips_mti_none_elf.rs
@@ -0,0 +1,36 @@
+use crate::abi::Endian;
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub(crate) fn target() -> Target {
+    Target {
+        data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
+        llvm_target: "mips".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("MIPS32r2 BE Baremetal Softfloat".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
+        },
+        pointer_width: 32,
+        arch: "mips".into(),
+
+        options: TargetOptions {
+            vendor: "mti".into(),
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            endian: Endian::Big,
+            cpu: "mips32r2".into(),
+
+            max_atomic_width: Some(32),
+
+            features: "+mips32r2,+soft-float,+noabicalls".into(),
+            executables: true,
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            singlethread: true,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs
new file mode 100644
index 00000000000..a89c0fce88c
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/mipsel_mti_none_elf.rs
@@ -0,0 +1,36 @@
+use crate::abi::Endian;
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub(crate) fn target() -> Target {
+    Target {
+        data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
+        llvm_target: "mipsel".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("MIPS32r2 LE Baremetal Softfloat".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: None, // ?
+        },
+        pointer_width: 32,
+        arch: "mips".into(),
+
+        options: TargetOptions {
+            vendor: "mti".into(),
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            endian: Endian::Little,
+            cpu: "mips32r2".into(),
+
+            max_atomic_width: Some(32),
+
+            features: "+mips32r2,+soft-float,+noabicalls".into(),
+            executables: true,
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            singlethread: true,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 5372437b0d2..f594d20f928 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_span::{Symbol, sym};
 
-use crate::spec::Target;
+use crate::spec::{FloatAbi, Target};
 
 /// Features that control behaviour of rustc, rather than the codegen.
 /// These exist globally and are not in the target-specific lists below.
@@ -17,60 +17,34 @@ pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
 pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
 
 /// Stability information for target features.
-/// `Toggleability` is the type storing whether (un)stable features can be toggled:
-/// this is initially a function since it can depend on `Target`, but for stable hashing
-/// it needs to be something hashable to we have to make the type generic.
-#[derive(Debug, Clone)]
-pub enum Stability<Toggleability> {
+#[derive(Debug, Copy, Clone)]
+pub enum Stability {
     /// This target feature is stable, it can be used in `#[target_feature]` and
     /// `#[cfg(target_feature)]`.
-    Stable {
-        /// When enabling/disabling the feature via `-Ctarget-feature` or `#[target_feature]`,
-        /// determine if that is allowed.
-        allow_toggle: Toggleability,
-    },
+    Stable,
     /// This target feature is unstable. It is only present in `#[cfg(target_feature)]` on
     /// nightly and using it in `#[target_feature]` requires enabling the given nightly feature.
-    Unstable {
+    Unstable(
         /// This must be a *language* feature, or else rustc will ICE when reporting a missing
         /// feature gate!
-        nightly_feature: Symbol,
-        /// See `Stable::allow_toggle` comment above.
-        allow_toggle: Toggleability,
-    },
+        Symbol,
+    ),
     /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be
     /// set in the target spec. It is never set in `cfg(target_feature)`. Used in
-    /// particular for features that change the floating-point ABI.
+    /// particular for features are actually ABI configuration flags (not all targets are as nice as
+    /// RISC-V and have an explicit way to set the ABI separate from target features).
     Forbidden { reason: &'static str },
 }
+use Stability::*;
 
-/// Returns `Ok` if the toggle is allowed, `Err` with an explanation of not.
-/// The `bool` indicates whether the feature is being enabled (`true`) or disabled.
-pub type AllowToggleUncomputed = fn(&Target, bool) -> Result<(), &'static str>;
-
-/// The computed result of whether a feature can be enabled/disabled on the current target.
-#[derive(Debug, Clone)]
-pub struct AllowToggleComputed {
-    enable: Result<(), &'static str>,
-    disable: Result<(), &'static str>,
-}
-
-/// `Stability` where `allow_toggle` has not been computed yet.
-pub type StabilityUncomputed = Stability<AllowToggleUncomputed>;
-/// `Stability` where `allow_toggle` has already been computed.
-pub type StabilityComputed = Stability<AllowToggleComputed>;
-
-impl<CTX, Toggleability: HashStable<CTX>> HashStable<CTX> for Stability<Toggleability> {
+impl<CTX> HashStable<CTX> for Stability {
     #[inline]
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         std::mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
-            Stability::Stable { allow_toggle } => {
-                allow_toggle.hash_stable(hcx, hasher);
-            }
-            Stability::Unstable { nightly_feature, allow_toggle } => {
+            Stability::Stable => {}
+            Stability::Unstable(nightly_feature) => {
                 nightly_feature.hash_stable(hcx, hasher);
-                allow_toggle.hash_stable(hcx, hasher);
             }
             Stability::Forbidden { reason } => {
                 reason.hash_stable(hcx, hasher);
@@ -79,16 +53,7 @@ impl<CTX, Toggleability: HashStable<CTX>> HashStable<CTX> for Stability<Toggleab
     }
 }
 
-impl<CTX> HashStable<CTX> for AllowToggleComputed {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        let AllowToggleComputed { enable, disable } = self;
-        enable.hash_stable(hcx, hasher);
-        disable.hash_stable(hcx, hasher);
-    }
-}
-
-impl<Toggleability> Stability<Toggleability> {
+impl Stability {
     /// Returns whether the feature can be used in `cfg(target_feature)` ever.
     /// (It might still be nightly-only even if this returns `true`, so make sure to also check
     /// `requires_nightly`.)
@@ -106,59 +71,23 @@ impl<Toggleability> Stability<Toggleability> {
     /// - for `cfg(target_feature)`, check `in_cfg`
     pub fn requires_nightly(&self) -> Option<Symbol> {
         match *self {
-            Stability::Unstable { nightly_feature, .. } => Some(nightly_feature),
+            Stability::Unstable(nightly_feature) => Some(nightly_feature),
             Stability::Stable { .. } => None,
             Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
         }
     }
-}
 
-impl StabilityUncomputed {
-    pub fn compute_toggleability(&self, target: &Target) -> StabilityComputed {
-        use Stability::*;
-        let compute = |f: AllowToggleUncomputed| AllowToggleComputed {
-            enable: f(target, true),
-            disable: f(target, false),
-        };
-        match *self {
-            Stable { allow_toggle } => Stable { allow_toggle: compute(allow_toggle) },
-            Unstable { nightly_feature, allow_toggle } => {
-                Unstable { nightly_feature, allow_toggle: compute(allow_toggle) }
-            }
-            Forbidden { reason } => Forbidden { reason },
-        }
-    }
-
-    pub fn toggle_allowed(&self, target: &Target, enable: bool) -> Result<(), &'static str> {
-        use Stability::*;
-        match *self {
-            Stable { allow_toggle } => allow_toggle(target, enable),
-            Unstable { allow_toggle, .. } => allow_toggle(target, enable),
-            Forbidden { reason } => Err(reason),
-        }
-    }
-}
-
-impl StabilityComputed {
     /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
     /// (It might still be nightly-only even if this returns `true`, so make sure to also check
     /// `requires_nightly`.)
-    pub fn toggle_allowed(&self, enable: bool) -> Result<(), &'static str> {
-        let allow_toggle = match self {
-            Stability::Stable { allow_toggle } => allow_toggle,
-            Stability::Unstable { allow_toggle, .. } => allow_toggle,
-            Stability::Forbidden { reason } => return Err(reason),
-        };
-        if enable { allow_toggle.enable } else { allow_toggle.disable }
+    pub fn toggle_allowed(&self) -> Result<(), &'static str> {
+        match self {
+            Stability::Forbidden { reason } => Err(reason),
+            _ => Ok(()),
+        }
     }
 }
 
-// Constructors for the list below, defaulting to "always allow toggle".
-const STABLE: StabilityUncomputed = Stability::Stable { allow_toggle: |_target, _enable| Ok(()) };
-const fn unstable(nightly_feature: Symbol) -> StabilityUncomputed {
-    Stability::Unstable { nightly_feature, allow_toggle: |_target, _enable| Ok(()) }
-}
-
 // Here we list target features that rustc "understands": they can be used in `#[target_feature]`
 // and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with
 // `-Ctarget-feature`.
@@ -204,218 +133,182 @@ const fn unstable(nightly_feature: Symbol) -> StabilityUncomputed {
 // Both of these are also applied transitively.
 type ImpliedFeatures = &'static [&'static str];
 
-const ARM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("aclass", unstable(sym::arm_target_feature), &[]),
-    ("aes", unstable(sym::arm_target_feature), &["neon"]),
-    ("crc", unstable(sym::arm_target_feature), &[]),
-    ("d32", unstable(sym::arm_target_feature), &[]),
-    ("dotprod", unstable(sym::arm_target_feature), &["neon"]),
-    ("dsp", unstable(sym::arm_target_feature), &[]),
-    ("fp-armv8", unstable(sym::arm_target_feature), &["vfp4"]),
-    (
-        "fpregs",
-        Stability::Unstable {
-            nightly_feature: sym::arm_target_feature,
-            allow_toggle: |target: &Target, _enable| {
-                // Only allow toggling this if the target has `soft-float` set. With `soft-float`,
-                // `fpregs` isn't needed so changing it cannot affect the ABI.
-                if target.has_feature("soft-float") {
-                    Ok(())
-                } else {
-                    Err("unsound on hard-float targets because it changes float ABI")
-                }
-            },
-        },
-        &[],
-    ),
-    ("i8mm", unstable(sym::arm_target_feature), &["neon"]),
-    ("mclass", unstable(sym::arm_target_feature), &[]),
-    ("neon", unstable(sym::arm_target_feature), &["vfp3"]),
-    ("rclass", unstable(sym::arm_target_feature), &[]),
-    ("sha2", unstable(sym::arm_target_feature), &["neon"]),
-    ("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]),
+    ("aclass", Unstable(sym::arm_target_feature), &[]),
+    ("aes", Unstable(sym::arm_target_feature), &["neon"]),
+    ("crc", Unstable(sym::arm_target_feature), &[]),
+    ("d32", Unstable(sym::arm_target_feature), &[]),
+    ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
+    ("dsp", Unstable(sym::arm_target_feature), &[]),
+    ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
+    ("fpregs", Unstable(sym::arm_target_feature), &[]),
+    ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
+    ("mclass", Unstable(sym::arm_target_feature), &[]),
+    ("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
+    ("rclass", Unstable(sym::arm_target_feature), &[]),
+    ("sha2", Unstable(sym::arm_target_feature), &["neon"]),
     // This is needed for inline assembly, but shouldn't be stabilized as-is
     // since it should be enabled per-function using #[instruction_set], not
     // #[target_feature].
-    ("thumb-mode", unstable(sym::arm_target_feature), &[]),
-    ("thumb2", unstable(sym::arm_target_feature), &[]),
-    ("trustzone", unstable(sym::arm_target_feature), &[]),
-    ("v5te", unstable(sym::arm_target_feature), &[]),
-    ("v6", unstable(sym::arm_target_feature), &["v5te"]),
-    ("v6k", unstable(sym::arm_target_feature), &["v6"]),
-    ("v6t2", unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
-    ("v7", unstable(sym::arm_target_feature), &["v6t2"]),
-    ("v8", unstable(sym::arm_target_feature), &["v7"]),
-    ("vfp2", unstable(sym::arm_target_feature), &[]),
-    ("vfp3", unstable(sym::arm_target_feature), &["vfp2", "d32"]),
-    ("vfp4", unstable(sym::arm_target_feature), &["vfp3"]),
-    ("virtualization", unstable(sym::arm_target_feature), &[]),
+    ("thumb-mode", Unstable(sym::arm_target_feature), &[]),
+    ("thumb2", Unstable(sym::arm_target_feature), &[]),
+    ("trustzone", Unstable(sym::arm_target_feature), &[]),
+    ("v5te", Unstable(sym::arm_target_feature), &[]),
+    ("v6", Unstable(sym::arm_target_feature), &["v5te"]),
+    ("v6k", Unstable(sym::arm_target_feature), &["v6"]),
+    ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
+    ("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
+    ("v8", Unstable(sym::arm_target_feature), &["v7"]),
+    ("vfp2", Unstable(sym::arm_target_feature), &[]),
+    ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
+    ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
+    ("virtualization", Unstable(sym::arm_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     // FEAT_AES & FEAT_PMULL
-    ("aes", STABLE, &["neon"]),
+    ("aes", Stable, &["neon"]),
     // FEAT_BF16
-    ("bf16", STABLE, &[]),
+    ("bf16", Stable, &[]),
     // FEAT_BTI
-    ("bti", STABLE, &[]),
+    ("bti", Stable, &[]),
     // FEAT_CRC
-    ("crc", STABLE, &[]),
+    ("crc", Stable, &[]),
     // FEAT_CSSC
-    ("cssc", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_DIT
-    ("dit", STABLE, &[]),
+    ("dit", Stable, &[]),
     // FEAT_DotProd
-    ("dotprod", STABLE, &["neon"]),
+    ("dotprod", Stable, &["neon"]),
     // FEAT_DPB
-    ("dpb", STABLE, &[]),
+    ("dpb", Stable, &[]),
     // FEAT_DPB2
-    ("dpb2", STABLE, &["dpb"]),
+    ("dpb2", Stable, &["dpb"]),
     // FEAT_ECV
-    ("ecv", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_F32MM
-    ("f32mm", STABLE, &["sve"]),
+    ("f32mm", Stable, &["sve"]),
     // FEAT_F64MM
-    ("f64mm", STABLE, &["sve"]),
+    ("f64mm", Stable, &["sve"]),
     // FEAT_FAMINMAX
-    ("faminmax", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_FCMA
-    ("fcma", STABLE, &["neon"]),
+    ("fcma", Stable, &["neon"]),
     // FEAT_FHM
-    ("fhm", STABLE, &["fp16"]),
+    ("fhm", Stable, &["fp16"]),
     // FEAT_FLAGM
-    ("flagm", STABLE, &[]),
+    ("flagm", Stable, &[]),
     // FEAT_FLAGM2
-    ("flagm2", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]),
+    // We forbid directly toggling just `fp-armv8`; it must be toggled with `neon`.
     ("fp-armv8", Stability::Forbidden { reason: "Rust ties `fp-armv8` to `neon`" }, &[]),
     // FEAT_FP16
     // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
-    ("fp16", STABLE, &["neon"]),
+    ("fp16", Stable, &["neon"]),
     // FEAT_FP8
-    ("fp8", unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]),
+    ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]),
     // FEAT_FP8DOT2
-    ("fp8dot2", unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]),
+    ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]),
     // FEAT_FP8DOT4
-    ("fp8dot4", unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]),
+    ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]),
     // FEAT_FP8FMA
-    ("fp8fma", unstable(sym::aarch64_unstable_target_feature), &["fp8"]),
+    ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]),
     // FEAT_FRINTTS
-    ("frintts", STABLE, &[]),
+    ("frintts", Stable, &[]),
     // FEAT_HBC
-    ("hbc", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_I8MM
-    ("i8mm", STABLE, &[]),
+    ("i8mm", Stable, &[]),
     // FEAT_JSCVT
     // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
-    ("jsconv", STABLE, &["neon"]),
+    ("jsconv", Stable, &["neon"]),
     // FEAT_LOR
-    ("lor", STABLE, &[]),
+    ("lor", Stable, &[]),
     // FEAT_LSE
-    ("lse", STABLE, &[]),
+    ("lse", Stable, &[]),
     // FEAT_LSE128
-    ("lse128", unstable(sym::aarch64_unstable_target_feature), &["lse"]),
+    ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]),
     // FEAT_LSE2
-    ("lse2", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_LUT
-    ("lut", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_MOPS
-    ("mops", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_MTE & FEAT_MTE2
-    ("mte", STABLE, &[]),
+    ("mte", Stable, &[]),
     // FEAT_AdvSimd & FEAT_FP
-    (
-        "neon",
-        Stability::Stable {
-            allow_toggle: |target, enable| {
-                if target.abi == "softfloat" {
-                    // `neon` has no ABI implications for softfloat targets, we can allow this.
-                    Ok(())
-                } else if enable
-                    && !target.has_neg_feature("fp-armv8")
-                    && !target.has_neg_feature("neon")
-                {
-                    // neon is enabled by default, and has not been disabled, so enabling it again
-                    // is redundant and we can permit it. Forbidding this would be a breaking change
-                    // since this feature is stable.
-                    Ok(())
-                } else {
-                    Err("unsound on hard-float targets because it changes float ABI")
-                }
-            },
-        },
-        &[],
-    ),
+    ("neon", Stable, &[]),
     // FEAT_PAUTH (address authentication)
-    ("paca", STABLE, &[]),
+    ("paca", Stable, &[]),
     // FEAT_PAUTH (generic authentication)
-    ("pacg", STABLE, &[]),
+    ("pacg", Stable, &[]),
     // FEAT_PAN
-    ("pan", STABLE, &[]),
+    ("pan", Stable, &[]),
     // FEAT_PAuth_LR
-    ("pauth-lr", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_PMUv3
-    ("pmuv3", STABLE, &[]),
+    ("pmuv3", Stable, &[]),
     // FEAT_RNG
-    ("rand", STABLE, &[]),
+    ("rand", Stable, &[]),
     // FEAT_RAS & FEAT_RASv1p1
-    ("ras", STABLE, &[]),
+    ("ras", Stable, &[]),
     // FEAT_LRCPC
-    ("rcpc", STABLE, &[]),
+    ("rcpc", Stable, &[]),
     // FEAT_LRCPC2
-    ("rcpc2", STABLE, &["rcpc"]),
+    ("rcpc2", Stable, &["rcpc"]),
     // FEAT_LRCPC3
-    ("rcpc3", unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]),
+    ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]),
     // FEAT_RDM
-    ("rdm", STABLE, &["neon"]),
+    ("rdm", Stable, &["neon"]),
     // This is needed for inline assembly, but shouldn't be stabilized as-is
     // since it should be enabled globally using -Zfixed-x18, not
     // #[target_feature].
     // Note that cfg(target_feature = "reserve-x18") is currently not set for
     // targets that reserve x18 by default.
-    ("reserve-x18", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_SB
-    ("sb", STABLE, &[]),
+    ("sb", Stable, &[]),
     // FEAT_SHA1 & FEAT_SHA256
-    ("sha2", STABLE, &["neon"]),
+    ("sha2", Stable, &["neon"]),
     // FEAT_SHA512 & FEAT_SHA3
-    ("sha3", STABLE, &["sha2"]),
+    ("sha3", Stable, &["sha2"]),
     // FEAT_SM3 & FEAT_SM4
-    ("sm4", STABLE, &["neon"]),
+    ("sm4", Stable, &["neon"]),
     // FEAT_SME
-    ("sme", unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
+    ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
     // FEAT_SME_B16B16
-    ("sme-b16b16", unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]),
+    ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]),
     // FEAT_SME_F16F16
-    ("sme-f16f16", unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
+    ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
     // FEAT_SME_F64F64
-    ("sme-f64f64", unstable(sym::aarch64_unstable_target_feature), &["sme"]),
+    ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
     // FEAT_SME_F8F16
-    ("sme-f8f16", unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]),
+    ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]),
     // FEAT_SME_F8F32
-    ("sme-f8f32", unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
+    ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
     // FEAT_SME_FA64
-    ("sme-fa64", unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]),
+    ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]),
     // FEAT_SME_I16I64
-    ("sme-i16i64", unstable(sym::aarch64_unstable_target_feature), &["sme"]),
+    ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
     // FEAT_SME_LUTv2
-    ("sme-lutv2", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_SME2
-    ("sme2", unstable(sym::aarch64_unstable_target_feature), &["sme"]),
+    ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]),
     // FEAT_SME2p1
-    ("sme2p1", unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
+    ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]),
     // FEAT_SPE
-    ("spe", STABLE, &[]),
+    ("spe", Stable, &[]),
     // FEAT_SSBS & FEAT_SSBS2
-    ("ssbs", STABLE, &[]),
+    ("ssbs", Stable, &[]),
     // FEAT_SSVE_FP8FDOT2
-    ("ssve-fp8dot2", unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]),
+    ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]),
     // FEAT_SSVE_FP8FDOT4
-    ("ssve-fp8dot4", unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]),
+    ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]),
     // FEAT_SSVE_FP8FMA
-    ("ssve-fp8fma", unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
+    ("ssve-fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]),
     // FEAT_SVE
     // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
     //
@@ -423,46 +316,46 @@ const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
     // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
     //
     // "For backwards compatibility, Neon and VFP are required in the latest architectures."
-    ("sve", STABLE, &["neon"]),
+    ("sve", Stable, &["neon"]),
     // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions)
-    ("sve-b16b16", unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
+    ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]),
     // FEAT_SVE2
-    ("sve2", STABLE, &["sve"]),
+    ("sve2", Stable, &["sve"]),
     // FEAT_SVE_AES & FEAT_SVE_PMULL128
-    ("sve2-aes", STABLE, &["sve2", "aes"]),
+    ("sve2-aes", Stable, &["sve2", "aes"]),
     // FEAT_SVE2_BitPerm
-    ("sve2-bitperm", STABLE, &["sve2"]),
+    ("sve2-bitperm", Stable, &["sve2"]),
     // FEAT_SVE2_SHA3
-    ("sve2-sha3", STABLE, &["sve2", "sha3"]),
+    ("sve2-sha3", Stable, &["sve2", "sha3"]),
     // FEAT_SVE2_SM4
-    ("sve2-sm4", STABLE, &["sve2", "sm4"]),
+    ("sve2-sm4", Stable, &["sve2", "sm4"]),
     // FEAT_SVE2p1
-    ("sve2p1", unstable(sym::aarch64_unstable_target_feature), &["sve2"]),
+    ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]),
     // FEAT_TME
-    ("tme", STABLE, &[]),
-    ("v8.1a", unstable(sym::aarch64_ver_target_feature), &[
+    ("tme", Stable, &[]),
+    ("v8.1a", Unstable(sym::aarch64_ver_target_feature), &[
         "crc", "lse", "rdm", "pan", "lor", "vh",
     ]),
-    ("v8.2a", unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
-    ("v8.3a", unstable(sym::aarch64_ver_target_feature), &[
+    ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
+    ("v8.3a", Unstable(sym::aarch64_ver_target_feature), &[
         "v8.2a", "rcpc", "paca", "pacg", "jsconv",
     ]),
-    ("v8.4a", unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
-    ("v8.5a", unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
-    ("v8.6a", unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
-    ("v8.7a", unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]),
-    ("v8.8a", unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]),
-    ("v8.9a", unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]),
-    ("v9.1a", unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]),
-    ("v9.2a", unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]),
-    ("v9.3a", unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]),
-    ("v9.4a", unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]),
-    ("v9.5a", unstable(sym::aarch64_ver_target_feature), &["v9.4a"]),
-    ("v9a", unstable(sym::aarch64_ver_target_feature), &["v8.5a", "sve2"]),
+    ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
+    ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
+    ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
+    ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]),
+    ("v8.8a", Unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]),
+    ("v8.9a", Unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]),
+    ("v9.1a", Unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]),
+    ("v9.2a", Unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]),
+    ("v9.3a", Unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]),
+    ("v9.4a", Unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]),
+    ("v9.5a", Unstable(sym::aarch64_ver_target_feature), &["v9.4a"]),
+    ("v9a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "sve2"]),
     // FEAT_VHE
-    ("vh", STABLE, &[]),
+    ("vh", Stable, &[]),
     // FEAT_WFxT
-    ("wfxt", unstable(sym::aarch64_unstable_target_feature), &[]),
+    ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
@@ -470,337 +363,260 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
     &["paca", "pacg"], // Together these represent `pauth` in LLVM
 ];
 
-const X86_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("adx", STABLE, &[]),
-    ("aes", STABLE, &["sse2"]),
-    ("amx-bf16", unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
-    ("amx-complex", unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
-    ("amx-fp16", unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
-    ("amx-int8", unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
-    ("amx-tile", unstable(sym::x86_amx_intrinsics), &[]),
-    ("avx", STABLE, &["sse4.2"]),
-    ("avx2", STABLE, &["avx"]),
-    ("avx512bf16", unstable(sym::avx512_target_feature), &["avx512bw"]),
-    ("avx512bitalg", unstable(sym::avx512_target_feature), &["avx512bw"]),
-    ("avx512bw", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avx512cd", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avx512dq", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avx512f", unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
-    ("avx512fp16", unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
-    ("avx512ifma", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avx512vbmi", unstable(sym::avx512_target_feature), &["avx512bw"]),
-    ("avx512vbmi2", unstable(sym::avx512_target_feature), &["avx512bw"]),
-    ("avx512vl", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avx512vnni", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avx512vp2intersect", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avx512vpopcntdq", unstable(sym::avx512_target_feature), &["avx512f"]),
-    ("avxifma", unstable(sym::avx512_target_feature), &["avx2"]),
-    ("avxneconvert", unstable(sym::avx512_target_feature), &["avx2"]),
-    ("avxvnni", unstable(sym::avx512_target_feature), &["avx2"]),
-    ("avxvnniint16", unstable(sym::avx512_target_feature), &["avx2"]),
-    ("avxvnniint8", unstable(sym::avx512_target_feature), &["avx2"]),
-    ("bmi1", STABLE, &[]),
-    ("bmi2", STABLE, &[]),
-    ("cmpxchg16b", STABLE, &[]),
-    ("ermsb", unstable(sym::ermsb_target_feature), &[]),
-    ("f16c", STABLE, &["avx"]),
-    ("fma", STABLE, &["avx"]),
-    ("fxsr", STABLE, &[]),
-    ("gfni", unstable(sym::avx512_target_feature), &["sse2"]),
-    ("lahfsahf", unstable(sym::lahfsahf_target_feature), &[]),
-    ("lzcnt", STABLE, &[]),
-    ("movbe", STABLE, &[]),
-    ("pclmulqdq", STABLE, &["sse2"]),
-    ("popcnt", STABLE, &[]),
-    ("prfchw", unstable(sym::prfchw_target_feature), &[]),
-    ("rdrand", STABLE, &[]),
-    ("rdseed", STABLE, &[]),
-    ("rtm", unstable(sym::rtm_target_feature), &[]),
-    ("sha", STABLE, &["sse2"]),
-    ("sha512", unstable(sym::sha512_sm_x86), &["avx2"]),
-    ("sm3", unstable(sym::sha512_sm_x86), &["avx"]),
-    ("sm4", unstable(sym::sha512_sm_x86), &["avx2"]),
+    ("adx", Stable, &[]),
+    ("aes", Stable, &["sse2"]),
+    ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
+    ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
+    ("avx", Stable, &["sse4.2"]),
+    ("avx2", Stable, &["avx"]),
+    ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
+    ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
+    ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
+    ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
+    ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
+    ("bmi1", Stable, &[]),
+    ("bmi2", Stable, &[]),
+    ("cmpxchg16b", Stable, &[]),
+    ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
+    ("f16c", Stable, &["avx"]),
+    ("fma", Stable, &["avx"]),
+    ("fxsr", Stable, &[]),
+    ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
+    ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
+    ("lzcnt", Stable, &[]),
+    ("movbe", Stable, &[]),
+    ("pclmulqdq", Stable, &["sse2"]),
+    ("popcnt", Stable, &[]),
+    ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
+    ("rdrand", Stable, &[]),
+    ("rdseed", Stable, &[]),
+    ("rtm", Unstable(sym::rtm_target_feature), &[]),
+    ("sha", Stable, &["sse2"]),
+    ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
+    ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
+    ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
     ("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]),
-    ("sse", STABLE, &[]),
-    ("sse2", STABLE, &["sse"]),
-    ("sse3", STABLE, &["sse2"]),
-    ("sse4.1", STABLE, &["ssse3"]),
-    ("sse4.2", STABLE, &["sse4.1"]),
-    ("sse4a", unstable(sym::sse4a_target_feature), &["sse3"]),
-    ("ssse3", STABLE, &["sse3"]),
-    ("tbm", unstable(sym::tbm_target_feature), &[]),
-    ("vaes", unstable(sym::avx512_target_feature), &["avx2", "aes"]),
-    ("vpclmulqdq", unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
-    (
-        "x87",
-        Stability::Unstable {
-            nightly_feature: sym::x87_target_feature,
-            allow_toggle: |target: &Target, _enable| {
-                // Only allow toggling this if the target has `soft-float` set. With `soft-float`,
-                // `fpregs` isn't needed so changing it cannot affect the ABI.
-                if target.has_feature("soft-float") {
-                    Ok(())
-                } else {
-                    Err("unsound on hard-float targets because it changes float ABI")
-                }
-            },
-        },
-        &[],
-    ),
-    ("xop", unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
-    ("xsave", STABLE, &[]),
-    ("xsavec", STABLE, &["xsave"]),
-    ("xsaveopt", STABLE, &["xsave"]),
-    ("xsaves", STABLE, &["xsave"]),
+    ("sse", Stable, &[]),
+    ("sse2", Stable, &["sse"]),
+    ("sse3", Stable, &["sse2"]),
+    ("sse4.1", Stable, &["ssse3"]),
+    ("sse4.2", Stable, &["sse4.1"]),
+    ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
+    ("ssse3", Stable, &["sse3"]),
+    ("tbm", Unstable(sym::tbm_target_feature), &[]),
+    ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
+    ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
+    ("x87", Unstable(sym::x87_target_feature), &[]),
+    ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
+    ("xsave", Stable, &[]),
+    ("xsavec", Stable, &["xsave"]),
+    ("xsaveopt", Stable, &["xsave"]),
+    ("xsaves", Stable, &["xsave"]),
     // tidy-alphabetical-end
 ];
 
-const HEXAGON_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("hvx", unstable(sym::hexagon_target_feature), &[]),
-    ("hvx-length128b", unstable(sym::hexagon_target_feature), &["hvx"]),
+    ("hvx", Unstable(sym::hexagon_target_feature), &[]),
+    ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
     // tidy-alphabetical-end
 ];
 
-const POWERPC_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("altivec", unstable(sym::powerpc_target_feature), &[]),
-    ("partword-atomics", unstable(sym::powerpc_target_feature), &[]),
-    ("power10-vector", unstable(sym::powerpc_target_feature), &["power9-vector"]),
-    ("power8-altivec", unstable(sym::powerpc_target_feature), &["altivec"]),
-    ("power8-crypto", unstable(sym::powerpc_target_feature), &["power8-altivec"]),
-    ("power8-vector", unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
-    ("power9-altivec", unstable(sym::powerpc_target_feature), &["power8-altivec"]),
-    ("power9-vector", unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
-    ("quadword-atomics", unstable(sym::powerpc_target_feature), &[]),
-    ("vsx", unstable(sym::powerpc_target_feature), &["altivec"]),
+    ("altivec", Unstable(sym::powerpc_target_feature), &[]),
+    ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]),
+    ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
+    ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
+    ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
+    ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
+    ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
+    ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
+    ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]),
+    ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
     // tidy-alphabetical-end
 ];
 
-const MIPS_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("fp64", unstable(sym::mips_target_feature), &[]),
-    ("msa", unstable(sym::mips_target_feature), &[]),
-    ("virt", unstable(sym::mips_target_feature), &[]),
+    ("fp64", Unstable(sym::mips_target_feature), &[]),
+    ("msa", Unstable(sym::mips_target_feature), &[]),
+    ("virt", Unstable(sym::mips_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const RISCV_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("a", STABLE, &["zaamo", "zalrsc"]),
-    ("c", STABLE, &[]),
-    (
-        "d",
-        Stability::Unstable {
-            nightly_feature: sym::riscv_target_feature,
-            allow_toggle: |target, enable| match &*target.llvm_abiname {
-                "ilp32d" | "lp64d" if !enable => {
-                    // The ABI requires the `d` feature, so it cannot be disabled.
-                    Err("feature is required by ABI")
-                }
-                "ilp32e" if enable => {
-                    // ilp32e is incompatible with features that need aligned load/stores > 32 bits,
-                    // like `d`.
-                    Err("feature is incompatible with ABI")
-                }
-                _ => Ok(()),
-            },
-        },
-        &["f"],
-    ),
-    (
-        "e",
-        Stability::Unstable {
-            // Given that this is a negative feature, consider this before stabilizing:
-            // does it really make sense to enable this feature in an individual
-            // function with `#[target_feature]`?
-            nightly_feature: sym::riscv_target_feature,
-            allow_toggle: |target, enable| {
-                match &*target.llvm_abiname {
-                    _ if !enable => {
-                        // Disabling this feature means we can use more registers (x16-x31).
-                        // The "e" ABIs treat them as caller-save, so it is safe to use them only
-                        // in some parts of a program while the rest doesn't know they even exist.
-                        // On other ABIs, the feature is already disabled anyway.
-                        Ok(())
-                    }
-                    "ilp32e" | "lp64e" => {
-                        // Embedded ABIs should already have the feature anyway, it's fine to enable
-                        // it again from an ABI perspective.
-                        Ok(())
-                    }
-                    _ => {
-                        // *Not* an embedded ABI. Enabling `e` is invalid.
-                        Err("feature is incompatible with ABI")
-                    }
-                }
-            },
-        },
-        &[],
-    ),
-    (
-        "f",
-        Stability::Unstable {
-            nightly_feature: sym::riscv_target_feature,
-            allow_toggle: |target, enable| {
-                match &*target.llvm_abiname {
-                    "ilp32f" | "ilp32d" | "lp64f" | "lp64d" if !enable => {
-                        // The ABI requires the `f` feature, so it cannot be disabled.
-                        Err("feature is required by ABI")
-                    }
-                    _ => Ok(()),
-                }
-            },
-        },
-        &[],
-    ),
+    ("a", Stable, &["zaamo", "zalrsc"]),
+    ("c", Stable, &[]),
+    ("d", Unstable(sym::riscv_target_feature), &["f"]),
+    ("e", Unstable(sym::riscv_target_feature), &[]),
+    ("f", Unstable(sym::riscv_target_feature), &[]),
     (
         "forced-atomics",
         Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" },
         &[],
     ),
-    ("m", STABLE, &[]),
-    ("relax", unstable(sym::riscv_target_feature), &[]),
-    ("unaligned-scalar-mem", unstable(sym::riscv_target_feature), &[]),
-    ("v", unstable(sym::riscv_target_feature), &[]),
-    ("zaamo", unstable(sym::riscv_target_feature), &[]),
-    ("zabha", unstable(sym::riscv_target_feature), &["zaamo"]),
-    ("zalrsc", unstable(sym::riscv_target_feature), &[]),
-    ("zba", STABLE, &[]),
-    ("zbb", STABLE, &[]),
-    ("zbc", STABLE, &[]),
-    ("zbkb", STABLE, &[]),
-    ("zbkc", STABLE, &[]),
-    ("zbkx", STABLE, &[]),
-    ("zbs", STABLE, &[]),
-    ("zdinx", unstable(sym::riscv_target_feature), &["zfinx"]),
-    ("zfh", unstable(sym::riscv_target_feature), &["zfhmin"]),
-    ("zfhmin", unstable(sym::riscv_target_feature), &["f"]),
-    ("zfinx", unstable(sym::riscv_target_feature), &[]),
-    ("zhinx", unstable(sym::riscv_target_feature), &["zhinxmin"]),
-    ("zhinxmin", unstable(sym::riscv_target_feature), &["zfinx"]),
-    ("zk", STABLE, &["zkn", "zkr", "zkt"]),
-    ("zkn", STABLE, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
-    ("zknd", STABLE, &[]),
-    ("zkne", STABLE, &[]),
-    ("zknh", STABLE, &[]),
-    ("zkr", STABLE, &[]),
-    ("zks", STABLE, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
-    ("zksed", STABLE, &[]),
-    ("zksh", STABLE, &[]),
-    ("zkt", STABLE, &[]),
+    ("m", Stable, &[]),
+    ("relax", Unstable(sym::riscv_target_feature), &[]),
+    ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
+    ("v", Unstable(sym::riscv_target_feature), &[]),
+    ("zaamo", Unstable(sym::riscv_target_feature), &[]),
+    ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]),
+    ("zalrsc", Unstable(sym::riscv_target_feature), &[]),
+    ("zba", Stable, &[]),
+    ("zbb", Stable, &[]),
+    ("zbc", Stable, &[]),
+    ("zbkb", Stable, &[]),
+    ("zbkc", Stable, &[]),
+    ("zbkx", Stable, &[]),
+    ("zbs", Stable, &[]),
+    ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
+    ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
+    ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
+    ("zfinx", Unstable(sym::riscv_target_feature), &[]),
+    ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
+    ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
+    ("zk", Stable, &["zkn", "zkr", "zkt"]),
+    ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
+    ("zknd", Stable, &[]),
+    ("zkne", Stable, &[]),
+    ("zknh", Stable, &[]),
+    ("zkr", Stable, &[]),
+    ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
+    ("zksed", Stable, &[]),
+    ("zksh", Stable, &[]),
+    ("zkt", Stable, &[]),
     // tidy-alphabetical-end
 ];
 
-const WASM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("atomics", unstable(sym::wasm_target_feature), &[]),
-    ("bulk-memory", STABLE, &[]),
-    ("exception-handling", unstable(sym::wasm_target_feature), &[]),
-    ("extended-const", STABLE, &[]),
-    ("multivalue", STABLE, &[]),
-    ("mutable-globals", STABLE, &[]),
-    ("nontrapping-fptoint", STABLE, &[]),
-    ("reference-types", STABLE, &[]),
-    ("relaxed-simd", STABLE, &["simd128"]),
-    ("sign-ext", STABLE, &[]),
-    ("simd128", STABLE, &[]),
-    ("tail-call", STABLE, &[]),
-    ("wide-arithmetic", unstable(sym::wasm_target_feature), &[]),
+    ("atomics", Unstable(sym::wasm_target_feature), &[]),
+    ("bulk-memory", Stable, &[]),
+    ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
+    ("extended-const", Stable, &[]),
+    ("multivalue", Stable, &[]),
+    ("mutable-globals", Stable, &[]),
+    ("nontrapping-fptoint", Stable, &[]),
+    ("reference-types", Stable, &[]),
+    ("relaxed-simd", Stable, &["simd128"]),
+    ("sign-ext", Stable, &[]),
+    ("simd128", Stable, &[]),
+    ("tail-call", Stable, &[]),
+    ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const BPF_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] =
-    &[("alu32", unstable(sym::bpf_target_feature), &[])];
+const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
+    &[("alu32", Unstable(sym::bpf_target_feature), &[])];
 
-const CSKY_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("10e60", unstable(sym::csky_target_feature), &["7e10"]),
-    ("2e3", unstable(sym::csky_target_feature), &["e2"]),
-    ("3e3r1", unstable(sym::csky_target_feature), &[]),
-    ("3e3r2", unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
-    ("3e3r3", unstable(sym::csky_target_feature), &["doloop"]),
-    ("3e7", unstable(sym::csky_target_feature), &["2e3"]),
-    ("7e10", unstable(sym::csky_target_feature), &["3e7"]),
-    ("cache", unstable(sym::csky_target_feature), &[]),
-    ("doloop", unstable(sym::csky_target_feature), &[]),
-    ("dsp1e2", unstable(sym::csky_target_feature), &[]),
-    ("dspe60", unstable(sym::csky_target_feature), &[]),
-    ("e1", unstable(sym::csky_target_feature), &["elrw"]),
-    ("e2", unstable(sym::csky_target_feature), &["e2"]),
-    ("edsp", unstable(sym::csky_target_feature), &[]),
-    ("elrw", unstable(sym::csky_target_feature), &[]),
-    ("float1e2", unstable(sym::csky_target_feature), &[]),
-    ("float1e3", unstable(sym::csky_target_feature), &[]),
-    ("float3e4", unstable(sym::csky_target_feature), &[]),
-    ("float7e60", unstable(sym::csky_target_feature), &[]),
-    ("floate1", unstable(sym::csky_target_feature), &[]),
-    ("hard-tp", unstable(sym::csky_target_feature), &[]),
-    ("high-registers", unstable(sym::csky_target_feature), &[]),
-    ("hwdiv", unstable(sym::csky_target_feature), &[]),
-    ("mp", unstable(sym::csky_target_feature), &["2e3"]),
-    ("mp1e2", unstable(sym::csky_target_feature), &["3e7"]),
-    ("nvic", unstable(sym::csky_target_feature), &[]),
-    ("trust", unstable(sym::csky_target_feature), &[]),
-    ("vdsp2e60f", unstable(sym::csky_target_feature), &[]),
-    ("vdspv1", unstable(sym::csky_target_feature), &[]),
-    ("vdspv2", unstable(sym::csky_target_feature), &[]),
+    ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
+    ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
+    ("3e3r1", Unstable(sym::csky_target_feature), &[]),
+    ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
+    ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
+    ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
+    ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
+    ("cache", Unstable(sym::csky_target_feature), &[]),
+    ("doloop", Unstable(sym::csky_target_feature), &[]),
+    ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
+    ("dspe60", Unstable(sym::csky_target_feature), &[]),
+    ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
+    ("e2", Unstable(sym::csky_target_feature), &["e2"]),
+    ("edsp", Unstable(sym::csky_target_feature), &[]),
+    ("elrw", Unstable(sym::csky_target_feature), &[]),
+    ("float1e2", Unstable(sym::csky_target_feature), &[]),
+    ("float1e3", Unstable(sym::csky_target_feature), &[]),
+    ("float3e4", Unstable(sym::csky_target_feature), &[]),
+    ("float7e60", Unstable(sym::csky_target_feature), &[]),
+    ("floate1", Unstable(sym::csky_target_feature), &[]),
+    ("hard-tp", Unstable(sym::csky_target_feature), &[]),
+    ("high-registers", Unstable(sym::csky_target_feature), &[]),
+    ("hwdiv", Unstable(sym::csky_target_feature), &[]),
+    ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
+    ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
+    ("nvic", Unstable(sym::csky_target_feature), &[]),
+    ("trust", Unstable(sym::csky_target_feature), &[]),
+    ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
+    ("vdspv1", Unstable(sym::csky_target_feature), &[]),
+    ("vdspv2", Unstable(sym::csky_target_feature), &[]),
     // tidy-alphabetical-end
     //fpu
     // tidy-alphabetical-start
-    ("fdivdu", unstable(sym::csky_target_feature), &[]),
-    ("fpuv2_df", unstable(sym::csky_target_feature), &[]),
-    ("fpuv2_sf", unstable(sym::csky_target_feature), &[]),
-    ("fpuv3_df", unstable(sym::csky_target_feature), &[]),
-    ("fpuv3_hf", unstable(sym::csky_target_feature), &[]),
-    ("fpuv3_hi", unstable(sym::csky_target_feature), &[]),
-    ("fpuv3_sf", unstable(sym::csky_target_feature), &[]),
-    ("hard-float", unstable(sym::csky_target_feature), &[]),
-    ("hard-float-abi", unstable(sym::csky_target_feature), &[]),
+    ("fdivdu", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
+    ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
+    ("hard-float", Unstable(sym::csky_target_feature), &[]),
+    ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const LOONGARCH_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("d", unstable(sym::loongarch_target_feature), &["f"]),
-    ("f", unstable(sym::loongarch_target_feature), &[]),
-    ("frecipe", unstable(sym::loongarch_target_feature), &[]),
-    ("lasx", unstable(sym::loongarch_target_feature), &["lsx"]),
-    ("lbt", unstable(sym::loongarch_target_feature), &[]),
-    ("lsx", unstable(sym::loongarch_target_feature), &["d"]),
-    ("lvz", unstable(sym::loongarch_target_feature), &[]),
-    ("relax", unstable(sym::loongarch_target_feature), &[]),
-    ("ual", unstable(sym::loongarch_target_feature), &[]),
+    ("d", Unstable(sym::loongarch_target_feature), &["f"]),
+    ("f", Unstable(sym::loongarch_target_feature), &[]),
+    ("frecipe", Unstable(sym::loongarch_target_feature), &[]),
+    ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
+    ("lbt", Unstable(sym::loongarch_target_feature), &[]),
+    ("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
+    ("lvz", Unstable(sym::loongarch_target_feature), &[]),
+    ("relax", Unstable(sym::loongarch_target_feature), &[]),
+    ("ual", Unstable(sym::loongarch_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const IBMZ_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("backchain", unstable(sym::s390x_target_feature), &[]),
-    ("vector", unstable(sym::s390x_target_feature), &[]),
+    ("backchain", Unstable(sym::s390x_target_feature), &[]),
+    ("vector", Unstable(sym::s390x_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const SPARC_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("leoncasa", unstable(sym::sparc_target_feature), &[]),
-    ("v8plus", unstable(sym::sparc_target_feature), &[]),
-    ("v9", unstable(sym::sparc_target_feature), &[]),
+    ("leoncasa", Unstable(sym::sparc_target_feature), &[]),
+    ("v8plus", Unstable(sym::sparc_target_feature), &[]),
+    ("v9", Unstable(sym::sparc_target_feature), &[]),
     // tidy-alphabetical-end
 ];
 
-const M68K_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
+const M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
-    ("isa-68000", unstable(sym::m68k_target_feature), &[]),
-    ("isa-68010", unstable(sym::m68k_target_feature), &["isa-68000"]),
-    ("isa-68020", unstable(sym::m68k_target_feature), &["isa-68010"]),
-    ("isa-68030", unstable(sym::m68k_target_feature), &["isa-68020"]),
-    ("isa-68040", unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]),
-    ("isa-68060", unstable(sym::m68k_target_feature), &["isa-68040"]),
+    ("isa-68000", Unstable(sym::m68k_target_feature), &[]),
+    ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]),
+    ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]),
+    ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]),
+    ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]),
+    ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]),
     // FPU
-    ("isa-68881", unstable(sym::m68k_target_feature), &[]),
-    ("isa-68882", unstable(sym::m68k_target_feature), &["isa-68881"]),
+    ("isa-68881", Unstable(sym::m68k_target_feature), &[]),
+    ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]),
     // tidy-alphabetical-end
 ];
 
@@ -808,7 +624,7 @@ const M68K_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
 /// primitives may be documented.
 ///
 /// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
-pub fn all_rust_features() -> impl Iterator<Item = (&'static str, StabilityUncomputed)> {
+pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
     std::iter::empty()
         .chain(ARM_FEATURES.iter())
         .chain(AARCH64_FEATURES.iter())
@@ -853,10 +669,16 @@ const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(
 const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
     &[(128, "lsx"), (256, "lasx")];
 
+#[derive(Copy, Clone, Debug)]
+pub struct FeatureConstraints {
+    /// Features that must be enabled.
+    pub required: &'static [&'static str],
+    /// Features that must be disabled.
+    pub incompatible: &'static [&'static str],
+}
+
 impl Target {
-    pub fn rust_target_features(
-        &self,
-    ) -> &'static [(&'static str, StabilityUncomputed, ImpliedFeatures)] {
+    pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
         match &*self.arch {
             "arm" => ARM_FEATURES,
             "aarch64" | "arm64ec" => AARCH64_FEATURES,
@@ -904,27 +726,130 @@ impl Target {
         }
     }
 
-    pub fn implied_target_features(
+    pub fn implied_target_features<'a>(
         &self,
-        base_features: impl Iterator<Item = Symbol>,
-    ) -> FxHashSet<Symbol> {
-        let implied_features = self
-            .rust_target_features()
-            .iter()
-            .map(|(f, _, i)| (Symbol::intern(f), i))
-            .collect::<FxHashMap<_, _>>();
+        base_features: impl Iterator<Item = &'a str>,
+    ) -> FxHashSet<&'a str> {
+        let implied_features =
+            self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::<FxHashMap<_, _>>();
 
         // implied target features have their own implied target features, so we traverse the
         // map until there are no more features to add
         let mut features = FxHashSet::default();
-        let mut new_features = base_features.collect::<Vec<Symbol>>();
+        let mut new_features = base_features.collect::<Vec<&str>>();
         while let Some(new_feature) = new_features.pop() {
             if features.insert(new_feature) {
                 if let Some(implied_features) = implied_features.get(&new_feature) {
-                    new_features.extend(implied_features.iter().copied().map(Symbol::intern))
+                    new_features.extend(implied_features.iter().copied())
                 }
             }
         }
         features
     }
+
+    /// Returns two lists of features:
+    /// the first list contains target features that must be enabled for ABI reasons,
+    /// and the second list contains target feature that must be disabled for ABI reasons.
+    ///
+    /// These features are automatically appended to whatever the target spec sats as default
+    /// features for the target.
+    ///
+    /// All features enabled/disabled via `-Ctarget-features` and `#[target_features]` are checked
+    /// against this. We also check any implied features, based on the information above. If LLVM
+    /// implicitly enables more implied features than we do, that could bypass this check!
+    pub fn abi_required_features(&self) -> FeatureConstraints {
+        const NOTHING: FeatureConstraints = FeatureConstraints { required: &[], incompatible: &[] };
+        // Some architectures don't have a clean explicit ABI designation; instead, the ABI is
+        // defined by target features. When that is the case, those target features must be
+        // "forbidden" in the list above to ensure that there is a consistent answer to the
+        // questions "which ABI is used".
+        match &*self.arch {
+            "x86" => {
+                // We support 2 ABIs, hardfloat (default) and softfloat.
+                // x86 has no sane ABI indicator so we have to use the target feature.
+                if self.has_feature("soft-float") {
+                    NOTHING
+                } else {
+                    // Hardfloat ABI. x87 must be enabled.
+                    FeatureConstraints { required: &["x87"], incompatible: &[] }
+                }
+            }
+            "x86_64" => {
+                // We support 2 ABIs, hardfloat (default) and softfloat.
+                // x86 has no sane ABI indicator so we have to use the target feature.
+                if self.has_feature("soft-float") {
+                    NOTHING
+                } else {
+                    // Hardfloat ABI. x87 and SSE2 must be enabled.
+                    FeatureConstraints { required: &["x87", "sse2"], incompatible: &[] }
+                }
+            }
+            "arm" => {
+                // On ARM, ABI handling is reasonably sane; we use `llvm_floatabi` to indicate
+                // to LLVM which ABI we are going for.
+                match self.llvm_floatabi.unwrap() {
+                    FloatAbi::Soft => {
+                        // Nothing special required, will use soft-float ABI throughout.
+                        NOTHING
+                    }
+                    FloatAbi::Hard => {
+                        // Must have `fpregs` and must not have `soft-float`.
+                        FeatureConstraints { required: &["fpregs"], incompatible: &["soft-float"] }
+                    }
+                }
+            }
+            "aarch64" | "arm64ec" => {
+                // Aarch64 has no sane ABI specifier, and LLVM doesn't even have a way to force
+                // the use of soft-float, so all we can do here is some crude hacks.
+                match &*self.abi {
+                    "softfloat" => {
+                        // This is not fully correct, LLVM actually doesn't let us enforce the softfloat
+                        // ABI properly... see <https://github.com/rust-lang/rust/issues/134375>.
+                        // FIXME: should we forbid "neon" here? But that would be a breaking change.
+                        NOTHING
+                    }
+                    _ => {
+                        // Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
+                        // These are Rust feature names and we use "neon" to control both of them.
+                        FeatureConstraints { required: &["neon"], incompatible: &[] }
+                    }
+                }
+            }
+            "riscv32" | "riscv64" => {
+                // RISC-V handles ABI in a very sane way, being fully explicit via `llvm_abiname`
+                // about what the intended ABI is.
+                match &*self.llvm_abiname {
+                    "ilp32d" | "lp64d" => {
+                        // Requires d (which implies f), incompatible with e.
+                        FeatureConstraints { required: &["d"], incompatible: &["e"] }
+                    }
+                    "ilp32f" | "lp64f" => {
+                        // Requires f, incompatible with e.
+                        FeatureConstraints { required: &["f"], incompatible: &["e"] }
+                    }
+                    "ilp32" | "lp64" => {
+                        // Requires nothing, incompatible with e.
+                        FeatureConstraints { required: &[], incompatible: &["e"] }
+                    }
+                    "ilp32e" => {
+                        // ilp32e is documented to be incompatible with features that need aligned
+                        // load/stores > 32 bits, like `d`. (One could also just generate more
+                        // complicated code to align the stack when needed, but the RISCV
+                        // architecture manual just explicitly rules out this combination so we
+                        // might as well.)
+                        // Note that the `e` feature is not required: the ABI treats the extra
+                        // registers as caller-save, so it is safe to use them only in some parts of
+                        // a program while the rest doesn't know they even exist.
+                        FeatureConstraints { required: &[], incompatible: &["d"] }
+                    }
+                    "lp64e" => {
+                        // As above, `e` is not required.
+                        NOTHING
+                    }
+                    _ => unreachable!(),
+                }
+            }
+            _ => NOTHING,
+        }
+    }
 }
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 40edd2c211c..207c744ee22 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -4,21 +4,21 @@ version = 4
 
 [[package]]
 name = "addr2line"
-version = "0.22.0"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
  "compiler_builtins",
- "gimli 0.29.0",
+ "gimli",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
-name = "adler"
-version = "1.0.2"
+name = "adler2"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -113,17 +113,6 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "gimli"
 version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
@@ -177,11 +166,11 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.4"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
+checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
 dependencies = [
- "adler",
+ "adler2",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -408,7 +397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "51f06a05848f650946acef3bf525fe96612226b61f74ae23ffa4e98bfbb8ab3c"
 dependencies = [
  "compiler_builtins",
- "gimli 0.31.1",
+ "gimli",
  "rustc-std-workspace-core",
 ]
 
diff --git a/library/Cargo.toml b/library/Cargo.toml
index e744cfe5e0f..e59aa518804 100644
--- a/library/Cargo.toml
+++ b/library/Cargo.toml
@@ -32,7 +32,7 @@ codegen-units = 10000
 [profile.release.package]
 addr2line.debug = 0
 addr2line.opt-level = "s"
-adler.debug = 0
+adler2.debug = 0
 gimli.debug = 0
 gimli.opt-level = "s"
 miniz_oxide.debug = 0
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index ae34fc65326..e9b7f985667 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -339,7 +339,7 @@ unsafe impl Allocator for Global {
     }
 }
 
-/// The allocator for unique pointers.
+/// The allocator for `Box`.
 #[cfg(all(not(no_global_oom_handling), not(test)))]
 #[lang = "exchange_malloc"]
 #[inline]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 05e5d712a27..0f66217b5cb 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -233,6 +233,27 @@ pub struct Box<
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
 >(Unique<T>, A);
 
+/// Constructs a `Box<T>` by calling the `exchange_malloc` lang item and moving the argument into
+/// the newly allocated memory. This is an intrinsic to avoid unnecessary copies.
+///
+/// This is the surface syntax for `box <expr>` expressions.
+#[cfg(not(bootstrap))]
+#[rustc_intrinsic]
+#[rustc_intrinsic_must_be_overridden]
+#[unstable(feature = "liballoc_internals", issue = "none")]
+pub fn box_new<T>(_x: T) -> Box<T> {
+    unreachable!()
+}
+
+/// Transition function for the next bootstrap bump.
+#[cfg(bootstrap)]
+#[unstable(feature = "liballoc_internals", issue = "none")]
+#[inline(always)]
+pub fn box_new<T>(x: T) -> Box<T> {
+    #[rustc_box]
+    Box::new(x)
+}
+
 impl<T> Box<T> {
     /// Allocates memory on the heap and then places `x` into it.
     ///
@@ -250,8 +271,7 @@ impl<T> Box<T> {
     #[rustc_diagnostic_item = "box_new"]
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub fn new(x: T) -> Self {
-        #[rustc_box]
-        Box::new(x)
+        return box_new(x);
     }
 
     /// Constructs a new box with uninitialized contents.
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 40759cb0ba8..aff90f5abb3 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -168,6 +168,7 @@
 #![feature(dropck_eyepatch)]
 #![feature(fundamental)]
 #![feature(hashmap_internals)]
+#![feature(intrinsics)]
 #![feature(lang_items)]
 #![feature(min_specialization)]
 #![feature(multiple_supertrait_upcastable)]
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index 8c6a367869c..6ee3907cc8e 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -48,10 +48,9 @@ macro_rules! vec {
     );
     ($($x:expr),+ $(,)?) => (
         <[_]>::into_vec(
-            // This rustc_box is not required, but it produces a dramatic improvement in compile
+            // Using the intrinsic produces a dramatic improvement in compile
             // time when constructing arrays with many elements.
-            #[rustc_box]
-            $crate::boxed::Box::new([$($x),+])
+            $crate::boxed::box_new([$($x),+])
         )
     );
 }
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 84679827ba1..2e654d3d1ff 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1204,22 +1204,16 @@ fn test_from_iter_specialization_with_iterator_adapters() {
 #[test]
 fn test_in_place_specialization_step_up_down() {
     fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {}
-    let src = vec![[0u8; 4]; 256];
-    let srcptr = src.as_ptr();
-    let src_cap = src.capacity();
-    let iter = src.into_iter().flatten();
-    assert_in_place_trait(&iter);
-    let sink = iter.collect::<Vec<_>>();
-    let sinkptr = sink.as_ptr();
-    assert_eq!(srcptr as *const u8, sinkptr);
-    assert_eq!(src_cap * 4, sink.capacity());
 
-    let iter = sink.into_iter().array_chunks::<4>();
+    let src = vec![0u8; 1024];
+    let srcptr = src.as_ptr();
+    let src_bytes = src.capacity();
+    let iter = src.into_iter().array_chunks::<4>();
     assert_in_place_trait(&iter);
     let sink = iter.collect::<Vec<_>>();
     let sinkptr = sink.as_ptr();
-    assert_eq!(srcptr, sinkptr);
-    assert_eq!(src_cap, sink.capacity());
+    assert_eq!(srcptr.addr(), sinkptr.addr());
+    assert_eq!(src_bytes, sink.capacity() * 4);
 
     let mut src: Vec<u8> = Vec::with_capacity(17);
     let src_bytes = src.capacity();
@@ -1236,13 +1230,6 @@ fn test_in_place_specialization_step_up_down() {
     let sink: Vec<[u8; 2]> = iter.collect();
     assert_eq!(sink.len(), 8);
     assert!(sink.capacity() <= 25);
-
-    let src = vec![[0u8; 4]; 256];
-    let srcptr = src.as_ptr();
-    let iter = src.into_iter().flat_map(|a| a.into_iter().map(|b| b.wrapping_add(1)));
-    assert_in_place_trait(&iter);
-    let sink = iter.collect::<Vec<_>>();
-    assert_eq!(srcptr as *const u8, sink.as_ptr());
 }
 
 #[test]
@@ -1350,6 +1337,20 @@ fn test_collect_after_iterator_clone() {
     assert_eq!(v, [1, 1, 1, 1, 1]);
     assert!(v.len() <= v.capacity());
 }
+
+// regression test for #135103, similar to the one above Flatten/FlatMap had an unsound InPlaceIterable
+// implementation.
+#[test]
+fn test_flatten_clone() {
+    const S: String = String::new();
+
+    let v = vec![[S, "Hello World!".into()], [S, S]];
+    let mut i = v.into_iter().flatten();
+    let _ = i.next();
+    let result: Vec<String> = i.clone().collect();
+    assert_eq!(result, ["Hello World!", "", ""]);
+}
+
 #[test]
 fn test_cow_from() {
     let borrowed: &[_] = &["borrowed", "(slice)"];
diff --git a/library/backtrace b/library/backtrace
-Subproject 4d7906bb24ae91ee6587127020d360f5298f9e7
+Subproject f8cc6ac9acc4e663ecd96f9bcf1ff4542636d1b
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 0023b46031f..9b9353b800a 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -1,7 +1,7 @@
 use crate::iter::adapters::SourceIter;
 use crate::iter::{
-    Cloned, Copied, Empty, Filter, FilterMap, Fuse, FusedIterator, InPlaceIterable, Map, Once,
-    OnceWith, TrustedFused, TrustedLen,
+    Cloned, Copied, Empty, Filter, FilterMap, Fuse, FusedIterator, Map, Once, OnceWith,
+    TrustedFused, TrustedLen,
 };
 use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
@@ -158,21 +158,6 @@ where
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I, U, F> InPlaceIterable for FlatMap<I, U, F>
-where
-    I: InPlaceIterable,
-    U: BoundedSize + IntoIterator,
-{
-    const EXPAND_BY: Option<NonZero<usize>> = const {
-        match (I::EXPAND_BY, U::UPPER_BOUND) {
-            (Some(m), Some(n)) => m.checked_mul(n),
-            _ => None,
-        }
-    };
-    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I, U, F> SourceIter for FlatMap<I, U, F>
 where
     I: SourceIter + TrustedFused,
@@ -387,21 +372,6 @@ where
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I> InPlaceIterable for Flatten<I>
-where
-    I: InPlaceIterable + Iterator,
-    <I as Iterator>::Item: IntoIterator + BoundedSize,
-{
-    const EXPAND_BY: Option<NonZero<usize>> = const {
-        match (I::EXPAND_BY, I::Item::UPPER_BOUND) {
-            (Some(m), Some(n)) => m.checked_mul(n),
-            _ => None,
-        }
-    };
-    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
-}
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I> SourceIter for Flatten<I>
 where
     I: SourceIter + TrustedFused + Iterator,
diff --git a/library/core/src/iter/sources/from_fn.rs b/library/core/src/iter/sources/from_fn.rs
index 3cd3830471c..5f3d404d7dc 100644
--- a/library/core/src/iter/sources/from_fn.rs
+++ b/library/core/src/iter/sources/from_fn.rs
@@ -3,6 +3,8 @@ use crate::fmt;
 /// Creates a new iterator where each iteration calls the provided closure
 /// `F: FnMut() -> Option<T>`.
 ///
+/// The iterator will yield the `T`s returned from the closure.
+///
 /// This allows creating a custom iterator with any behavior
 /// without using the more verbose syntax of creating a dedicated type
 /// and implementing the [`Iterator`] trait for it.
diff --git a/library/core/src/iter/sources/successors.rs b/library/core/src/iter/sources/successors.rs
index 36bc4035039..e14c9235e55 100644
--- a/library/core/src/iter/sources/successors.rs
+++ b/library/core/src/iter/sources/successors.rs
@@ -5,6 +5,7 @@ use crate::iter::FusedIterator;
 ///
 /// The iterator starts with the given first item (if any)
 /// and calls the given `FnMut(&T) -> Option<T>` closure to compute each item’s successor.
+/// The iterator will yield the `T`s returned from the closure.
 ///
 /// ```
 /// use std::iter::successors;
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 073cca7daef..f800e0d391c 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -987,8 +987,9 @@ impl<T> [T] {
     /// assert!(v == [3, 2, 1]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_slice_reverse", issue = "135120")]
     #[inline]
-    pub fn reverse(&mut self) {
+    pub const fn reverse(&mut self) {
         let half_len = self.len() / 2;
         let Range { start, end } = self.as_mut_ptr_range();
 
@@ -1011,7 +1012,7 @@ impl<T> [T] {
         revswap(front_half, back_half, half_len);
 
         #[inline]
-        fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
+        const fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
             debug_assert!(a.len() == n);
             debug_assert!(b.len() == n);
 
@@ -1019,7 +1020,8 @@ impl<T> [T] {
             // this check tells LLVM that the indexing below is
             // in-bounds. Then after inlining -- once the actual
             // lengths of the slices are known -- it's removed.
-            let (a, b) = (&mut a[..n], &mut b[..n]);
+            let (a, _) = a.split_at_mut(n);
+            let (b, _) = b.split_at_mut(n);
 
             let mut i = 0;
             while i < n {
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 6380c941e6a..e7f7f38cb41 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -30,8 +30,8 @@ std_detect = { path = "../stdarch/crates/std_detect", default-features = false,
 rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
-miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
-addr2line = { version = "0.22.0", optional = true, default-features = false }
+miniz_oxide = { version = "0.8.0", optional = true, default-features = false }
+addr2line = { version = "0.24.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
 libc = { version = "0.2.169", default-features = false, features = [
diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs
index 5231a34469a..044dc2e8cd8 100644
--- a/library/std/src/sys/pal/windows/os.rs
+++ b/library/std/src/sys/pal/windows/os.rs
@@ -5,8 +5,9 @@
 #[cfg(test)]
 mod tests;
 
-use super::api::{self, WinError};
-use super::to_u16s;
+#[cfg(not(target_vendor = "uwp"))]
+use super::api::WinError;
+use super::{api, to_u16s};
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::os::windows::ffi::EncodeWide;
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index c4780cc56b2..3657d9b3112 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -440,7 +440,7 @@ fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: boo
 }
 
 pub fn dir_is_empty(dir: &Path) -> bool {
-    t!(std::fs::read_dir(dir)).next().is_none()
+    t!(std::fs::read_dir(dir), dir).next().is_none()
 }
 
 /// Extract the beta revision from the full version string.
diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md
index 2a686b5471c..7ce7d4ddf3e 100644
--- a/src/doc/rustc-dev-guide/README.md
+++ b/src/doc/rustc-dev-guide/README.md
@@ -70,46 +70,21 @@ $ ENABLE_LINKCHECK=1 mdbook serve
 We use `mdbook-toc` to auto-generate TOCs for long sections. You can invoke the preprocessor by
 including the `<!-- toc -->` marker at the place where you want the TOC.
 
-## How to fix toolstate failures
-
-> [!NOTE]
-> Currently, we do not track the rustc-dev-guide toolstate due to
-> [spurious failures](https://github.com/rust-lang/rust/pull/71731),
-> but we leave these instructions for when we do it again in the future.
-
-1. You will get a ping from the toolstate commit. e.g. https://github.com/rust-lang-nursery/rust-toolstate/commit/8ffa0e4c30ac9ba8546b7046e5c4ccc2b96ebdd4
-
-2. The commit contains a link to the PR that caused the breakage. e.g. https://github.com/rust-lang/rust/pull/64321
-
-3. If you go to that PR's thread, there is a post from bors with a link to the CI status: https://github.com/rust-lang/rust/pull/64321#issuecomment-529763807
-
-4. Follow the check-actions link to get to the Actions page for that build
-
-5. There will be approximately 1 billion different jobs for the build. They are for different configurations and platforms. The rustc-dev-guide build only runs on the Linux x86_64-gnu-tools job. So click on that job in the list, which is about 60% down in the list.
-
-6. Click the Run build step in the job to get the console log for the step.
-
-7. Click on the log and Ctrl-f to get a search box in the log
-
-8. Search for rustc-dev-guide. This gets you to the place where the links are checked. It is usually ~11K lines into the log.
-
-9. Look at the links in the log near that point in the log
-
-10. Fix those links in the rustc-dev-guide (by making a PR in the rustc-dev-guide repo)
-
-11. Make a PR on the rust-lang/rust repo to update the rustc-dev-guide git submodule in src/docs/rustc-dev-guide.
-To make a PR, the following steps are useful.
-
-```bash
-# Assuming you already cloned the rust-lang/rust repo and you're in the correct directory
-git submodule update --remote src/doc/rustc-dev-guide
-git add -u
-git commit -m "Update rustc-dev-guide"
-# Note that you can use -i, which is short for --incremental, in the following command
-./x test --incremental src/doc/rustc-dev-guide # This is optional and should succeed anyway
-# Open a PR in rust-lang/rust
-```
-
-12. Wait for PR to merge
-
-Voilà!
+## Synchronizing josh subtree with rustc
+
+This repository is linked to `rust-lang/rust` as a [josh](https://josh-project.github.io/josh/intro.html) subtree. You can use the following commands to synchronize the subtree in both directions.
+
+### Pull changes from `rust-lang/rust` into this repository
+1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide`
+2) Run the pull command
+    ```
+    $ cargo run --manifest-path josh-sync/Cargo.toml rustc-pull
+    ```
+3) Push the branch to your fork and create a PR into `rustc-dev-guide`
+
+### Push changes from this repository into `rust-lang/rust`
+1) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
+    ```
+    $ cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username>
+    ```
+2) Create a PR from `<branch-name>` into `rust-lang/rust`
diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.lock b/src/doc/rustc-dev-guide/josh-sync/Cargo.lock
new file mode 100644
index 00000000000..844518628c4
--- /dev/null
+++ b/src/doc/rustc-dev-guide/josh-sync/Cargo.lock
@@ -0,0 +1,430 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
+name = "directories"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "josh-sync"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "directories",
+ "xshell",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.169"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags",
+ "libc",
+]
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "xshell"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e7290c623014758632efe00737145b6867b66292c42167f2ec381eb566a373d"
+dependencies = [
+ "xshell-macros",
+]
+
+[[package]]
+name = "xshell-macros"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547"
diff --git a/src/doc/rustc-dev-guide/josh-sync/Cargo.toml b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml
new file mode 100644
index 00000000000..81d0d1ebd22
--- /dev/null
+++ b/src/doc/rustc-dev-guide/josh-sync/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "josh-sync"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+anyhow = "1.0.95"
+clap = { version = "4.5.21", features = ["derive"] }
+directories = "5"
+xshell = "0.2.6"
diff --git a/src/doc/rustc-dev-guide/josh-sync/README.md b/src/doc/rustc-dev-guide/josh-sync/README.md
new file mode 100644
index 00000000000..a3dd876e8b8
--- /dev/null
+++ b/src/doc/rustc-dev-guide/josh-sync/README.md
@@ -0,0 +1,4 @@
+# Git josh sync
+This utility serves for syncing the josh git subtree to and from the rust-lang/rust repository.
+
+See CLI help for usage.
diff --git a/src/doc/rustc-dev-guide/josh-sync/src/main.rs b/src/doc/rustc-dev-guide/josh-sync/src/main.rs
new file mode 100644
index 00000000000..84613ad8689
--- /dev/null
+++ b/src/doc/rustc-dev-guide/josh-sync/src/main.rs
@@ -0,0 +1,32 @@
+use clap::Parser;
+use crate::sync::GitSync;
+
+mod sync;
+
+#[derive(clap::Parser)]
+enum Args {
+    /// Pull changes from the main `rustc` repository.
+    /// This creates new commits that should be then merged into `rustc-dev-guide`.
+    RustcPull,
+    /// Push changes from `rustc-dev-guide` to the given `branch` of a `rustc` fork under the given
+    /// GitHub `username`.
+    /// The pushed branch should then be merged into the `rustc` repository.
+    RustcPush {
+        branch: String,
+        github_username: String
+    }
+}
+
+fn main() -> anyhow::Result<()> {
+    let args = Args::parse();
+    let sync = GitSync::from_current_dir()?;
+    match args {
+        Args::RustcPull => {
+            sync.rustc_pull(None)?;
+        }
+        Args::RustcPush { github_username, branch } => {
+            sync.rustc_push(github_username, branch)?;
+        }
+    }
+    Ok(())
+}
diff --git a/src/doc/rustc-dev-guide/josh-sync/src/sync.rs b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
new file mode 100644
index 00000000000..da21a4c9a27
--- /dev/null
+++ b/src/doc/rustc-dev-guide/josh-sync/src/sync.rs
@@ -0,0 +1,234 @@
+use std::ops::Not;
+use std::path::PathBuf;
+use std::{env, net, process};
+use std::io::Write;
+use std::time::Duration;
+use anyhow::{anyhow, bail, Context};
+use xshell::{cmd, Shell};
+
+/// Used for rustc syncs.
+const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide";
+const JOSH_PORT: u16 = 42042;
+const UPSTREAM_REPO: &str = "rust-lang/rust";
+
+pub struct GitSync {
+    dir: PathBuf,
+}
+
+/// This code was adapted from the miri repository
+/// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236).
+impl GitSync {
+    pub fn from_current_dir() -> anyhow::Result<Self> {
+        Ok(Self {
+            dir: std::env::current_dir()?
+        })
+    }
+
+    pub fn rustc_pull(&self, commit: Option<String>) -> anyhow::Result<()> {
+        let sh = Shell::new()?;
+        sh.change_dir(&self.dir);
+        let commit = commit.map(Ok).unwrap_or_else(|| {
+            let rust_repo_head =
+                cmd!(sh, "git ls-remote https://github.com/{UPSTREAM_REPO}/ HEAD").read()?;
+            rust_repo_head
+                .split_whitespace()
+                .next()
+                .map(|front| front.trim().to_owned())
+                .ok_or_else(|| anyhow!("Could not obtain Rust repo HEAD from remote."))
+        })?;
+        // Make sure the repo is clean.
+        if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
+            bail!("working directory must be clean before performing rustc pull");
+        }
+        // Make sure josh is running.
+        let josh = Self::start_josh()?;
+        let josh_url =
+            format!("http://localhost:{JOSH_PORT}/{UPSTREAM_REPO}.git@{commit}{JOSH_FILTER}.git");
+
+        // Update rust-version file. As a separate commit, since making it part of
+        // the merge has confused the heck out of josh in the past.
+        // We pass `--no-verify` to avoid running git hooks.
+        // We do this before the merge so that if there are merge conflicts, we have
+        // the right rust-version file while resolving them.
+        sh.write_file("rust-version", format!("{commit}\n"))?;
+        const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
+        cmd!(sh, "git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}")
+            .run()
+            .context("FAILED to commit rust-version file, something went wrong")?;
+
+        // Fetch given rustc commit.
+        cmd!(sh, "git fetch {josh_url}")
+            .run()
+            .inspect_err(|_| {
+                // Try to un-do the previous `git commit`, to leave the repo in the state we found it.
+                cmd!(sh, "git reset --hard HEAD^")
+                    .run()
+                    .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
+            })
+            .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
+
+        // This should not add any new root commits. So count those before and after merging.
+        let num_roots = || -> anyhow::Result<u32> {
+            Ok(cmd!(sh, "git rev-list HEAD --max-parents=0 --count")
+                .read()
+                .context("failed to determine the number of root commits")?
+                .parse::<u32>()?)
+        };
+        let num_roots_before = num_roots()?;
+
+        // Merge the fetched commit.
+        const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
+        cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
+            .run()
+            .context("FAILED to merge new commits, something went wrong")?;
+
+        // Check that the number of roots did not increase.
+        if num_roots()? != num_roots_before {
+            bail!("Josh created a new root commit. This is probably not the history you want.");
+        }
+
+        drop(josh);
+        Ok(())
+    }
+
+    pub fn rustc_push(&self, github_user: String, branch: String) -> anyhow::Result<()> {
+        let sh = Shell::new()?;
+        sh.change_dir(&self.dir);
+        let base = sh.read_file("rust-version")?.trim().to_owned();
+        // Make sure the repo is clean.
+        if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
+            bail!("working directory must be clean before running `rustc-push`");
+        }
+        // Make sure josh is running.
+        let josh = Self::start_josh()?;
+        let josh_url =
+            format!("http://localhost:{JOSH_PORT}/{github_user}/rust.git{JOSH_FILTER}.git");
+
+        // Find a repo we can do our preparation in.
+        if let Ok(rustc_git) = env::var("RUSTC_GIT") {
+            // If rustc_git is `Some`, we'll use an existing fork for the branch updates.
+            sh.change_dir(rustc_git);
+        } else {
+            // Otherwise, do this in the local repo.
+            println!(
+                "This will pull a copy of the rust-lang/rust history into this checkout, growing it by about 1GB."
+            );
+            print!(
+                "To avoid that, abort now and set the `RUSTC_GIT` environment variable to an existing rustc checkout. Proceed? [y/N] "
+            );
+            std::io::stdout().flush()?;
+            let mut answer = String::new();
+            std::io::stdin().read_line(&mut answer)?;
+            if answer.trim().to_lowercase() != "y" {
+                std::process::exit(1);
+            }
+        };
+        // Prepare the branch. Pushing works much better if we use as base exactly
+        // the commit that we pulled from last time, so we use the `rust-version`
+        // file to find out which commit that would be.
+        println!("Preparing {github_user}/rust (base: {base})...");
+        if cmd!(sh, "git fetch https://github.com/{github_user}/rust {branch}")
+            .ignore_stderr()
+            .read()
+            .is_ok()
+        {
+            println!(
+                "The branch '{branch}' seems to already exist in 'https://github.com/{github_user}/rust'. Please delete it and try again."
+            );
+            std::process::exit(1);
+        }
+        cmd!(sh, "git fetch https://github.com/{UPSTREAM_REPO} {base}").run()?;
+        cmd!(sh, "git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}")
+            .ignore_stdout()
+            .ignore_stderr() // silence the "create GitHub PR" message
+            .run()?;
+        println!();
+
+        // Do the actual push.
+        sh.change_dir(&self.dir);
+        println!("Pushing changes...");
+        cmd!(sh, "git push {josh_url} HEAD:{branch}").run()?;
+        println!();
+
+        // Do a round-trip check to make sure the push worked as expected.
+        cmd!(sh, "git fetch {josh_url} {branch}").ignore_stderr().read()?;
+        let head = cmd!(sh, "git rev-parse HEAD").read()?;
+        let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
+        if head != fetch_head {
+            bail!(
+                "Josh created a non-roundtrip push! Do NOT merge this into rustc!\n\
+                Expected {head}, got {fetch_head}."
+            );
+        }
+        println!(
+            "Confirmed that the push round-trips back to rustc-dev-guide properly. Please create a rustc PR:"
+        );
+        println!(
+            // Open PR with `subtree update` title to silence the `no-merges` triagebot check
+            "    https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=Rustc+dev+guide+subtree+update&body=r?+@ghost"
+        );
+
+        drop(josh);
+        Ok(())
+    }
+
+    fn start_josh() -> anyhow::Result<impl Drop> {
+        // Determine cache directory.
+        let local_dir = {
+            let user_dirs =
+                directories::ProjectDirs::from("org", "rust-lang", "rustc-dev-guide-josh").unwrap();
+            user_dirs.cache_dir().to_owned()
+        };
+
+        // Start josh, silencing its output.
+        let mut cmd = process::Command::new("josh-proxy");
+        cmd.arg("--local").arg(local_dir);
+        cmd.arg("--remote").arg("https://github.com");
+        cmd.arg("--port").arg(JOSH_PORT.to_string());
+        cmd.arg("--no-background");
+        cmd.stdout(process::Stdio::null());
+        cmd.stderr(process::Stdio::null());
+        let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
+
+        // Create a wrapper that stops it on drop.
+        struct Josh(process::Child);
+        impl Drop for Josh {
+            fn drop(&mut self) {
+                #[cfg(unix)]
+                {
+                    // Try to gracefully shut it down.
+                    process::Command::new("kill")
+                        .args(["-s", "INT", &self.0.id().to_string()])
+                        .output()
+                        .expect("failed to SIGINT josh-proxy");
+                    // Sadly there is no "wait with timeout"... so we just give it some time to finish.
+                    std::thread::sleep(Duration::from_millis(100));
+                    // Now hopefully it is gone.
+                    if self.0.try_wait().expect("failed to wait for josh-proxy").is_some() {
+                        return;
+                    }
+                }
+                // If that didn't work (or we're not on Unix), kill it hard.
+                eprintln!(
+                    "I have to kill josh-proxy the hard way, let's hope this does not break anything."
+                );
+                self.0.kill().expect("failed to SIGKILL josh-proxy");
+            }
+        }
+
+        // Wait until the port is open. We try every 10ms until 1s passed.
+        for _ in 0..100 {
+            // This will generally fail immediately when the port is still closed.
+            let josh_ready = net::TcpStream::connect_timeout(
+                &net::SocketAddr::from(([127, 0, 0, 1], JOSH_PORT)),
+                Duration::from_millis(1),
+            );
+            if josh_ready.is_ok() {
+                return Ok(Josh(josh));
+            }
+            // Not ready yet.
+            std::thread::sleep(Duration::from_millis(10));
+        }
+        bail!("Even after waiting for 1s, josh-proxy is still not available.")
+    }
+}
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
new file mode 100644
index 00000000000..876c32dcf43
--- /dev/null
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -0,0 +1 @@
+dcfa38fe234de9304169afc6638e81d0dd222c06
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 2fbbb187d6b..a8fddbc7562 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -134,14 +134,13 @@
 
 - [Prologue](./part-4-intro.md)
 - [Generic parameter definitions](./generic_parameters_summary.md)
-    - [Implementation nuances of early/late bound parameters](./early-late-bound-params/early-late-bound-implementation-nuances.md)
-    - [Interactions with turbofishing](./early-late-bound-params/turbofishing-and-early-late-bound.md)
+    - [`EarlyBinder` and instantiating parameters](./ty_module/early_binder.md)
+- [Binders and Higher ranked regions](./ty_module/binders.md)
+    - [Instantiating binders](./ty_module/instantiating_binders.md)
+- [Early vs Late bound parameters](./early_late_parameters.md)
 - [The `ty` module: representing types](./ty.md)
     - [ADTs and Generic Arguments](./ty_module/generic_arguments.md)
     - [Parameter types/consts/regions](./ty_module/param_ty_const_regions.md)
-    - [`EarlyBinder` and instantiating parameters](./ty_module/early_binder.md)
-    - [`Binder` and Higher ranked regions](./ty_module/binders.md)
-    - [Instantiating binders](./ty_module/instantiating_binders.md)
 - [`TypeFolder` and `TypeFoldable`](./ty-fold.md)
 - [Parameter Environments](./param_env/param_env_summary.md)
     - [What is it?](./param_env/param_env_what_is_it.md)
diff --git a/src/doc/rustc-dev-guide/src/early-late-bound-params/early-late-bound-implementation-nuances.md b/src/doc/rustc-dev-guide/src/early-late-bound-params/early-late-bound-implementation-nuances.md
deleted file mode 100644
index 01569e8dc6a..00000000000
--- a/src/doc/rustc-dev-guide/src/early-late-bound-params/early-late-bound-implementation-nuances.md
+++ /dev/null
@@ -1,197 +0,0 @@
-# Early and Late Bound Parameter Implementation Nuances
-
-> Note: this chapter makes reference to information discussed later on in the [representing types][ch_representing_types] chapter. Specifically, it uses concise notation to represent some more complex kinds of types that have not yet been discussed, such as inference variables.
-
-[ch_representing_types]: ../ty.md
-
-Understanding this page likely requires a rudimentary understanding of higher ranked
-trait bounds/`for<'a>`and also what types such as `dyn for<'a> Trait<'a>` and
- `for<'a> fn(&'a u32)` mean. Reading [the nomincon chapter](https://doc.rust-lang.org/nomicon/hrtb.html)
-on HRTB may be useful for understanding this syntax. The meaning of `for<'a> fn(&'a u32)`
-is incredibly similar to the meaning of `T: for<'a> Trait<'a>`.
-
-## What does it mean for parameters to be early or late bound
-
-All function definitions conceptually have a ZST (this is represented by `TyKind::FnDef` in rustc).
-The only generics on this ZST are the early bound parameters of the function definition. e.g.
-```rust
-fn foo<'a>(_: &'a u32) {}
-
-fn main() {
-    let b = foo;
-    //  ^ `b` has type `FnDef(foo, [])` (no args because `'a` is late bound)
-    assert!(std::mem::size_of_val(&b) == 0);
-}
-```
-
-In order to call `b` the late bound parameters do need to be provided, these are inferred at the
-call site instead of when we refer to `foo`.
-```rust
-fn main() {
-    let b = foo;
-    let a: &'static u32 = &10;
-    foo(a);
-    // the lifetime argument for `'a` on `foo` is inferred at the callsite
-    // the generic parameter `'a` on `foo` is inferred to `'static` here
-}
-```
-
-Because late bound parameters are not part of the `FnDef`'s args this allows us to prove trait
-bounds such as `F: for<'a> Fn(&'a u32)` where `F` is `foo`'s `FnDef`. e.g.
-```rust
-fn foo_early<'a, T: Trait<'a>>(_: &'a u32, _: T) {}
-fn foo_late<'a, T>(_: &'a u32, _: T) {}
-
-fn accepts_hr_func<F: for<'a> Fn(&'a u32, u32)>(_: F) {}
-
-fn main() {
-    // doesn't work, the instantiated bound is `for<'a> FnDef<'?0>: Fn(&'a u32, u32)`
-    // `foo_early` only implements `for<'a> FnDef<'a>: Fn(&'a u32, u32)`- the lifetime
-    // of the borrow in the function argument must be the same as the lifetime
-    // on the `FnDef`.
-    accepts_hr_func(foo_early);
-
-    // works, the instantiated bound is `for<'a> FnDef: Fn(&'a u32, u32)`
-    accepts_hr_func(foo_late);
-}
-
-// the builtin `Fn` impls for `foo_early` and `foo_late` look something like:
-// `foo_early`
-impl<'a, T: Trait<'a>> Fn(&'a u32, T) for FooEarlyFnDef<'a, T> { ... }
-// `foo_late`
-impl<'a, T> Fn(&'a u32, T) for FooLateFnDef<T> { ... }
-
-```
-
-Early bound parameters are present on the `FnDef`. Late bound generic parameters are not present
-on the `FnDef` but are instead constrained by the builtin `Fn*` impl.
-
-The same distinction applies to closures. Instead of `FnDef` we are talking about the anonymous
-closure type. Closures are [currently unsound](https://github.com/rust-lang/rust/issues/84366) in
-ways that are closely related to the distinction between early/late bound
-parameters (more on this later)
-
-The early/late boundness of generic parameters is only relevant for the desugaring of
-functions/closures into types with builtin `Fn*` impls. It does not make sense to talk about
-in other contexts.
-
-The `generics_of` query in rustc only contains early bound parameters. In this way it acts more
-like `generics_of(my_func)` is the generics for the FnDef than the generics provided to the function
-body although it's not clear to the author of this section if this was the actual justification for
-making `generics_of` behave this way.
-
-## What parameters are currently late bound
-
-Below are the current requirements for determining if a generic parameter is late bound. It is worth
-keeping in mind that these are not necessarily set in stone and it is almost certainly possible to
-be more flexible.
-
-### Must be a lifetime parameter
-
-Rust can't support types such as `for<T> dyn Trait<T>` or `for<T> fn(T)`, this is a
-fundamental limitation of the language as we are required to monomorphize type/const
-parameters and cannot do so behind dynamic dispatch. (technically we could probably
-support `for<T> dyn MarkerTrait<T>` as there is nothing to monomorphize)
-
-Not being able to support `for<T> dyn Trait<T>` resulted in making all type and const
-parameters early bound. Only lifetime parameters can be late bound.
-
-### Must not appear in the where clauses
-
-In order for a generic parameter to be late bound it must not appear in any where clauses.
-This is currently an incredibly simplistic check that causes lifetimes to be early bound even
-if the where clause they appear in are always true, or implied by well formedness of function
-arguments. e.g.
-```rust
-fn foo1<'a: 'a>(_: &'a u32) {}
-//     ^^ early bound parameter because it's in a `'a: 'a` clause
-//        even though the bound obviously holds all the time
-fn foo2<'a, T: Trait<'a>(a: T, b: &'a u32) {}
-//     ^^ early bound parameter because it's used in the `T: Trait<'a>` clause
-fn foo3<'a, T: 'a>(_: &'a T) {}
-//     ^^ early bound parameter because it's used in the `T: 'a` clause
-//        even though that bound is implied by wellformedness of `&'a T`
-fn foo4<'a, 'b: 'a>(_: Inv<&'a ()>, _: Inv<&'b ()>) {}
-//      ^^  ^^         ^^^ note:
-//      ^^  ^^         `Inv` stands for `Invariant` and is used to
-//      ^^  ^^          make the type parameter invariant. This
-//      ^^  ^^          is necessary for demonstration purposes as
-//      ^^  ^^          `for<'a, 'b> fn(&'a (), &'b ())` and
-//      ^^  ^^          `for<'a> fn(&'a u32, &'a u32)` are subtypes-
-//      ^^  ^^          of each other which makes the bound trivially
-//      ^^  ^^          satisfiable when making the fnptr. `Inv`
-//      ^^  ^^          disables this subtyping.
-//      ^^  ^^
-//      ^^^^^^ both early bound parameters because they are present in the
-//            `'b: 'a` clause
-```
-
-The reason for this requirement is that we cannot represent the `T: Trait<'a>` or `'a: 'b` clauses
-on a function pointer. `for<'a, 'b> fn(Inv<&'a ()>, Inv<&'b ()>)` is not a valid function pointer to
-represent`foo4` as it would allow calling the function without `'b: 'a` holding.
-
-### Must be constrained by where clauses or function argument types
-
-The builtin impls of the `Fn*` traits for closures and `FnDef`s cannot not have any unconstrained
-parameters. For example the following impl is illegal:
-```rust
-impl<'a> Trait for u32 { type Assoc = &'a u32; }
-```
-We must not end up with a similar impl for the `Fn*` traits e.g.
-```rust
-impl<'a> Fn<()> for FnDef { type Assoc = &'a u32 }
-```
-
-Violating this rule can trivially lead to unsoundness as seen in [#84366](https://github.com/rust-lang/rust/issues/84366).
-Additionally if we ever support late bound type params then an impl like:
-```rust
-impl<T> Fn<()> for FnDef { type Assoc = T; }
-```
-would break the compiler in various ways.
-
-In order to ensure that everything functions correctly, we do not allow generic parameters to
-be late bound if it would result in a builtin impl that does not constrain all of the generic
-parameters on the builtin impl. Making a generic parameter be early bound trivially makes it be
-constrained by the builtin impl as it ends up on the self type.
-
-Because of the requirement that late bound parameters must not appear in where clauses, checking
-this is simpler than the rules for checking impl headers constrain all the parameters on the impl.
-We only have to ensure that all late bound parameters appear at least once in the function argument
-types outside of an alias (e.g. an associated type).
-
-The requirement that they not indirectly be in the args of an alias for it to count is the
-same as why the follow code is forbidden:
-```rust
-impl<T: Trait> OtherTrait for <T as Trait>::Assoc { type Assoc = T }
-```
-There is no guarantee that `<T as Trait>::Assoc` will normalize to different types for every
-instantiation of `T`. If we were to allow this impl we could get overlapping impls and the
-same is true of the builtin `Fn*` impls.
-
-## Making more generic parameters late bound
-
-It is generally considered desirable for more parameters to be late bound as it makes
-the builtin `Fn*` impls more flexible. Right now many of the requirements for making
-a parameter late bound are overly restrictive as they are tied to what we can currently
-(or can ever) do with fn ptrs.
-
-It would be theoretically possible to support late bound params in `where`-clauses in the
-language by introducing implication types which would allow us to express types such as:
-`for<'a, 'b: 'a> fn(Inv<&'a u32>, Inv<&'b u32>)` which would ensure `'b: 'a` is upheld when
-calling the function pointer.
-
-It would also be theoretically possible to support it by making the coercion to a fn ptr
-instantiate the parameter with an infer var while still allowing the FnDef to not have the
-generic parameter present as trait impls are perfectly capable of representing the where clauses
-on the function on the impl itself. This would also allow us to support late bound type/const
-vars allowing bounds like `F: for<T> Fn(T)` to hold.
-
-It is almost somewhat unclear if we can change the `Fn` traits to be structured differently
-so that we never have to make a parameter early bound just to make the builtin impl have all
-generics be constrained. Of all the possible causes of a generic parameter being early bound
-this seems the most difficult to remove.
-
-Whether these would be good ideas to implement is a separate question- they are only brought
-up to illustrate that the current rules are not necessarily set in stone and a result of
-"its the only way of doing this".
-
diff --git a/src/doc/rustc-dev-guide/src/early-late-bound-params/turbofishing-and-early-late-bound.md b/src/doc/rustc-dev-guide/src/early-late-bound-params/turbofishing-and-early-late-bound.md
deleted file mode 100644
index 6fc30c6767d..00000000000
--- a/src/doc/rustc-dev-guide/src/early-late-bound-params/turbofishing-and-early-late-bound.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# Turbofishing's interactions with early/late bound parameters
-
-> Note: this chapter makes reference to information discussed later on in the [representing types][ch_representing_types] chapter. Specifically, it uses concise notation to represent some more complex kinds of types that have not yet been discussed, such as inference variables.
-
-[ch_representing_types]: ../ty.md
-
-The early/late bound parameter distinction on functions introduces some complications
-when providing generic arguments to functions. This document discusses what those are
-and how they might interact with future changes to make more things late bound.
-
-## Can't turbofish generic arguments on functions sometimes
-
-When a function has any late bound lifetime parameters (be they explicitly defined or
-implicitly introduced via lifetime elision) we disallow specifying any lifetime arguments
-on the function. Sometimes this is a hard error other times it is a future compat lint
-([`late_bound_lifetime_arguments`](https://github.com/rust-lang/rust/issues/42868)).
-
-```rust
-fn early<'a: 'a>(a: &'a ()) -> &'a () { a }
-fn late<'a>(a: &'a ()) -> &'a () { a }
-
-fn mixed<'a, 'b: 'b>(a: &'a (), b: &'b ()) -> &'a () { a }
-
-struct Foo;
-impl Foo {
-    fn late<'a>(self, a: &'a ()) -> &'a () { a }
-}
-
-fn main() {
-    // fine
-    let f = early::<'static>;
-    
-    // some variation of hard errors and future compat lints
-    Foo.late::<'static>(&());
-    let f = late::<'static>;
-    let f = mixed::<'static, 'static>;
-    let f = mixed::<'static>;
-    late::<'static>(&());
-}
-```
-
-The justification for this is that late bound parameters are not present on the
-`FnDef` so the arguments to late bound parameters can't be present in the generic arguments
-for the type. i.e. the `late` function in the above code snippet would not have
-any generic parameters on the `FnDef` zst:
-```rust
-// example desugaring of the `late` function and its zst + builtin Fn impl
-struct LateFnDef;
-impl<'a> Fn<(&'a ())> for LateFnDef {
-    type Output = &'a ();
-    ...
-}
-```
-
-The cause for some situations giving future compat lints and others giving hard errors
-is a little arbitrary but explainable:
-- It's always a hard error for method calls
-- It's only a hard error on paths to free functions if there is no unambiguous way to
-create the generic arguments for the fndef from the lifetime arguments. (i.e. the amount of
-lifetimes provided must be exactly equal to the amount of early bound lifetimes or
-else it's a hard error)
-
-## Back compat issues from turning early bound to late bound
-
-Because of the previously mentioned restriction on turbofishing generic arguments, it
-is a breaking change to upgrade a lifetime from early bound to late bound as it can cause
-existing turbofishies to become hard errors/future compat lints.
-
-Many t-types members have expressed interest in wanting more parameters to be late bound.
-We cannot do so if making something late bound is going to break code that many would
-expect to work (judging by the future compat lint issue many people do expect to be able
-to turbofish late bound parameters).
-
-## Interactions with late bound type/const parameters
-
-If we were to make some type/const parameters late bound we would definitely not want
-to disallow turbofishing them as it presumably(?) would break a Tonne of code. 
-
-While lifetimes do differ from type/consts in some ways I(BoxyUwU) do not believe there
-is any justification for why it would make sense to allow turbofishing late bound
-type/const parameters but not late bound lifetimes.
-
-## Removing the hard error/fcw
-
-From reasons above it seems reasonable that we may want to remove the hard error and fcw
-(removing the errors/fcw is definitely a blocker for making more things late bound).
-
-example behaviour:
-```rust
-fn late<'a>(a: &'a ()) -> &'a () { a }
-
-fn accepts_fn(_: impl for<'a> Fn(&'a ()) -> &'a ()) {}
-fn accepts_fn_2(_: impl Fn(&'static ()) -> &'static ()) {}
-
-fn main() {
-    let f = late::<'static>;
-    
-    accepts_fn(f); //~ error: `f` doesn't implement `for<'a> Fn(&'a ()) -> &'a ()`
-    accepts_fn_2(f) // works
-    
-    accepts_fn(late) // works
-}
-````
-
-one potential complication is that we would want a way to specify a generic argument
-to a function without having to specify arguments for all previous parameters. i.e.
-ideally you could write the following code somehow.
-```rust
-fn late<'a, 'b>(_: &'a (), _: &'b ()) {}
-
-fn accepts_fn(_: impl for<'a> Fn(&'a (), &'static ())) {}
-
-fn main() {
-    // a naive implementation would have an inference variable as
-    // the argument to the `'a` parameter no longer allowing the `FnDef`
-    // to satisfy the bound `for<'a> Fn(&'a ())`
-    let f = late::<'_, 'static>;
-    accepts_fn(f);
-}
-```
-Maybe we can just special case HIR ty lowering for `_`/`'_` arguments for late bound
-parameters somehow and have it not mean the same thing as `_` for early bound parameters.
-Regardless I think we would need a solution that would allow writing the above code even
-if it was done by some new syntax such as having to write `late::<k#no_argument, 'static>`
-(naturally `k#no_argument` would only make sense as an argument to late bound parameters).
diff --git a/src/doc/rustc-dev-guide/src/early_late_parameters.md b/src/doc/rustc-dev-guide/src/early_late_parameters.md
new file mode 100644
index 00000000000..6d13655294d
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/early_late_parameters.md
@@ -0,0 +1,424 @@
+
+# Early vs Late bound parameters
+
+<!-- toc -->
+
+> **NOTE**: This chapter largely talks about early/late bound as being solely relevant when discussing function item types/function definitions. This is potentially not completely true, async blocks and closures should likely be discussed somewhat in this chapter.
+
+## What does it mean to be "early" bound or "late" bound
+
+Every function definition has a corresponding ZST that implements the `Fn*` traits known as a [function item type][function_item_type]. This part of the chapter will talk a little bit about the "desugaring" of function item types as it is useful context for explaining the difference between early bound and late bound generic parameters.
+
+Let's start with a very trivial example involving no generic parameters:
+
+```rust
+fn foo(a: String) -> u8 {
+    # 1
+    /* snip */
+}
+```
+
+If we explicitly wrote out the definitions for the function item type corresponding to `foo` and its associated `Fn` impl it would look something like this:
+```rust,ignore
+struct FooFnItem;
+
+impl Fn<(String,)> for FooFnItem {
+    type Output = u8;
+    /* fn call(&self, ...) -> ... { ... } */
+}
+```
+
+The builtin impls for the `FnMut`/`FnOnce` traits as well as the impls for `Copy` and `Clone` were omitted for brevity reasons (although these traits *are* implemented for function item types).
+
+A slightly more complicated example would involve introducing generic parameters to the function:
+```rust
+fn foo<T: Sized>(a: T) -> T { 
+    # a
+    /* snip */
+}
+```
+Writing out the definitions would look something like this:
+```rust,ignore
+struct FooFnItem<T: Sized>(PhantomData<fn(T) -> T>);
+
+impl<T: Sized> Fn<(T,)> for FooFnItem<T> {
+    type Output = T;
+    /* fn call(&self, ...) -> ... { ... } */
+}
+```
+
+Note that the function item type `FooFnItem` is generic over some type parameter `T` as defined on the function `foo`. However, not all generic parameters defined on functions are also defined on the function item type as demonstrated here:
+```rust
+fn foo<'a, T: Sized>(a: &'a T) -> &'a T {
+    # a
+    /* snip */
+}
+```
+With its "desugared" form looking like so:
+```rust,ignore
+struct FooFnItem<T: Sized>(PhantomData<for<'a> fn(&'a T) -> &'a T>);
+
+impl<'a, T: Sized> Fn<(&'a T,)> for FooFnItem<T> {
+    type Output = &'a T;
+    /* fn call(&self, ...) -> ... { ... } */
+}
+```
+
+The lifetime parameter `'a` from the function `foo` is not present on the function item type `FooFnItem` and is instead introduced on the builtin impl solely for use in representing the argument types.
+
+Generic parameters not all being defined on the function item type means that there are two steps where generic arguments are provided when calling a function.
+1. Naming the function (e.g. `let a = foo;`) the arguments for `FooFnItem` are provided. 
+2. Calling the function (e.g. `a(&10);`) any parameters defined on the builtin impl are provided.
+
+This two-step system is where the early vs late naming scheme comes from, early bound parameters are provided in the *earliest* step (naming the function), whereas late bound parameters are provided in the *latest* step (calling the function). 
+
+Looking at the desugaring from the previous example we can tell that `T` is an early bound type parameter and `'a` is a late bound lifetime parameter as `T` is present on the function item type but `'a` is not. See this example of calling `foo` annotated with where each generic parameter has an argument provided:
+```rust
+fn foo<'a, T: Sized>(a: &'a T) -> &'a T {
+    # a
+    /* snip */
+}
+
+// Here we provide a type argument `String` to the
+// type parameter `T` on the function item type
+let my_func = foo::<String>;
+
+// Here (implicitly) a lifetime argument is provided
+// to the lifetime parameter `'a` on the builtin impl.
+my_func(&String::new());
+```
+
+[function_item_type]: https://doc.rust-lang.org/reference/types/function-item.html
+
+## Differences between early and late bound parameters
+
+### Higher ranked function pointers and trait bounds 
+
+A generic parameter being late bound allows for more flexible usage of the function item. For example if we have some function `foo` with an early bound lifetime parameter and some function `bar` with a late bound lifetime parameter `'a` we would have the following builtin `Fn` impls:
+```rust,ignore
+impl<'a> Fn<(&'a String,)> for FooFnItem<'a> { /* ... */ }
+impl<'a> Fn<(&'a String,)> for BarFnItem { /* ... */ }
+```
+
+The `bar` function has a strictly more flexible signature as the function item type can be called with a borrow with *any* lifetime, whereas the `foo` function item type would only be callable with a borrow with the same lifetime on the function item type. We can show this by simply trying to call `foo`'s function item type multiple times with different lifetimes:
+
+```rust
+// The `'a: 'a` bound forces this lifetime to be early bound.
+fn foo<'a: 'a>(b: &'a String) -> &'a String { b }
+fn bar<'a>(b: &'a String) -> &'a String { b }
+
+// Early bound generic parameters are instantiated here when naming
+// the function `foo`. As `'a` is early bound an argument is provided.
+let f = foo::<'_>;
+
+// Both function arguments are required to have the same lifetime as
+// the lifetime parameter being early bound means that `f` is only
+// callable for one specific lifetime.
+//
+// As we call this with borrows of different lifetimes, the borrow checker
+// will error here.
+f(&String::new());
+f(&String::new());
+```
+
+In this example we call `foo`'s function item type twice, each time with a borrow of a temporary. These two borrows could not possible have lifetimes that overlap as the temporaries are only alive during the function call, not after. The lifetime parameter on `foo` being early bound requires all callers of `f` to provide a borrow with the same lifetime, as this is not possible the borrow checker errors.
+
+If the lifetime parameter on `foo` was late bound this would be able to compile as each caller could provide a different lifetime argument for its borrow. See the following example which demonstrates this using the `bar` function defined above:
+
+```rust
+#fn foo<'a: 'a>(b: &'a String) -> &'a String { b }
+#fn bar<'a>(b: &'a String) -> &'a String { b }
+
+// Early bound parameters are instantiated here, however as `'a` is
+// late bound it is not provided here.
+let b = bar;
+
+// Late bound parameters are instantiated separately at each call site
+// allowing different lifetimes to be used by each caller.
+b(&String::new());
+b(&String::new());
+```
+
+This is reflected in the ability to coerce function item types to higher ranked function pointers and prove higher ranked `Fn` trait bounds. We can demonstrate this with the following example:
+```rust
+// The `'a: 'a` bound forces this lifetime to be early bound.
+fn foo<'a: 'a>(b: &'a String) -> &'a String { b }
+fn bar<'a>(b: &'a String) -> &'a String { b }
+
+fn accepts_hr_fn(_: impl for<'a> Fn(&'a String) -> &'a String) {}
+
+fn higher_ranked_trait_bound() {
+    let bar_fn_item = bar;
+    accepts_hr_fn(bar_fn_item);
+
+    let foo_fn_item = foo::<'_>;
+    // errors
+    accepts_hr_fn(foo_fn_item);
+}
+
+fn higher_ranked_fn_ptr() {
+    let bar_fn_item = bar;
+    let fn_ptr: for<'a> fn(&'a String) -> &'a String = bar_fn_item;
+    
+    let foo_fn_item = foo::<'_>;
+    // errors
+    let fn_ptr: for<'a> fn(&'a String) -> &'a String = foo_fn_item;
+}
+```
+
+In both of these cases the borrow checker errors as it does not consider `foo_fn_item` to be callable with a borrow of any lifetime. This is due to the fact that the lifetime parameter on `foo` is early bound, causing `foo_fn_item` to have a type of `FooFnItem<'_>` which (as demonstrated by the desugared `Fn` impl) is only callable with a borrow of the same lifetime `'_`.
+
+### Turbofishing in the presence of late bound parameters
+
+As mentioned previously, the distinction between early and late bound parameters means that there are two places where generic parameters are instantiated:
+- When naming a function (early)
+- When calling a function (late)
+
+There currently is no syntax for explicitly specifying generic arguments for late bound parameters as part of the call step, only specifying generic arguments when naming a function. The syntax `foo::<'static>();`, despite being part of a function call, behaves as `(foo::<'static>)();` and instantiates the early bound generic parameters on the function item type.
+
+See the following example:
+```rust
+fn foo<'a>(b: &'a u32) -> &'a u32 { b }
+
+let f /* : FooFnItem<????> */ = foo::<'static>;
+```
+
+The above example errors as the lifetime parameter `'a` is late bound and so cannot be instantiated as part of the "naming a function" step. If we make the lifetime parameter early bound we will see this code start to compile:
+```rust
+fn foo<'a: 'a>(b: &'a u32) -> &'a u32 { b }
+
+let f /* : FooFnItem<'static> */ = foo::<'static>;
+```
+
+What the current implementation of the compiler aims to do is error when specifying lifetime arguments to a function that has both early *and* late bound lifetime parameters. In practice, due to excessive breakage, some cases are actually only future compatibility warnings ([#42868](https://github.com/rust-lang/rust/issues/42868)):
+- When the amount of lifetime arguments is the same as the number of early bound lifetime parameters a FCW is emitted instead of an error
+- An error is always downgraded to a FCW when using method call syntax
+
+To demonstrate this we can write out the different kinds of functions and give them both a late and early bound lifetime:
+```rust,ignore
+fn free_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+
+struct Foo;
+
+trait Trait: Sized {
+    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ());
+    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ());
+}
+
+impl Trait for Foo {
+    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+}
+
+impl Foo {
+    fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+    fn inherent_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+}
+```
+
+Then, for the first case, we can call each function with a single lifetime argument (corresponding to the one early bound lifetime parameter) and note that it only results in a FCW rather than a hard error.
+```rust
+#![deny(late_bound_lifetime_arguments)]
+
+#fn free_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+#
+#struct Foo;
+#
+#trait Trait: Sized {
+#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ());
+#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ());
+#}
+#
+#impl Trait for Foo {
+#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+#}
+#
+#impl Foo {
+#    fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#    fn inherent_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+#}
+#
+// Specifying as many arguments as there are early
+// bound parameters is always a future compat warning
+Foo.trait_method::<'static>(&(), &());
+Foo::trait_method::<'static>(Foo, &(), &());
+Foo::trait_function::<'static>(&(), &());
+Foo.inherent_method::<'static>(&(), &());
+Foo::inherent_function::<'static>(&(), &());
+free_function::<'static>(&(), &());
+```
+
+For the second case we call each function with more lifetime arguments than there are lifetime parameters (be it early or late bound) and note that method calls result in a FCW as opposed to the free/associated functions which result in a hard error:
+```rust
+#fn free_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+#
+#struct Foo;
+#
+#trait Trait: Sized {
+#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ());
+#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ());
+#}
+#
+#impl Trait for Foo {
+#    fn trait_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#    fn trait_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+#}
+#
+#impl Foo {
+#    fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b ()) {}
+#    fn inherent_function<'a: 'a, 'b>(_: &'a (), _: &'b ()) {}
+#}
+#
+// Specifying more arguments than there are early
+// bound parameters is a future compat warning when
+// using method call syntax.
+Foo.trait_method::<'static, 'static, 'static>(&(), &());
+Foo.inherent_method::<'static, 'static, 'static>(&(), &());
+// However, it is a hard error when not using method call syntax.
+Foo::trait_method::<'static, 'static, 'static>(Foo, &(), &());
+Foo::trait_function::<'static, 'static, 'static>(&(), &());
+Foo::inherent_function::<'static, 'static, 'static>(&(), &());
+free_function::<'static, 'static, 'static>(&(), &());
+```
+
+Even when specifying enough lifetime arguments for both the late and early bound lifetime parameter, these arguments are not actually used to annotate the lifetime provided to late bound parameters. We can demonstrate this by turbofishing `'static` to a function while providing a non-static borrow:
+```rust
+struct Foo;
+
+impl Foo {
+    fn inherent_method<'a: 'a, 'b>(self, _: &'a (), _: &'b String ) {}
+}
+
+Foo.inherent_method::<'static, 'static>(&(), &String::new());
+```
+
+This compiles even though the `&String::new()` function argument does not have a `'static` lifetime, this is because "extra" lifetime arguments are discarded rather than taken into account for late bound parameters when actually calling the function.
+
+### Liveness of types with late bound parameters
+
+When checking type outlives bounds involving function item types we take into account early bound parameters. For example:
+
+```rust
+fn foo<T>(_: T) {}
+
+fn requires_static<T: 'static>(_: T) {}
+
+fn bar<T>() {
+    let f /* : FooFnItem<T> */ = foo::<T>;
+    requires_static(f);
+}
+```
+
+As the type parameter `T` is early bound, the desugaring of the function item type for `foo` would look something like `struct FooFnItem<T>`. Then in order for `FooFnItem<T>: 'static` to hold we must also require `T: 'static` to hold as otherwise we would wind up with soundness bugs.
+
+Unfortunately, due to bugs in the compiler, we do not take into account early bound *lifetimes*, which is the cause of the open soundness bug [#84366](https://github.com/rust-lang/rust/issues/84366). This means that it's impossible to demonstrate a "difference" between early/late bound parameters for liveness/type outlives bounds as the only kind of generic parameters that are able to be late bound are lifetimes which are handled incorrectly.
+
+Regardless, in theory the code example below *should* demonstrate such a difference once [#84366](https://github.com/rust-lang/rust/issues/84366) is fixed:
+```rust
+fn early_bound<'a: 'a>(_: &'a String) {}
+fn late_bound<'a>(_: &'a String) {}
+
+fn requires_static<T: 'static>(_: T) {}
+
+fn bar<'b>() {
+    let e = early_bound::<'b>;
+    // this *should* error but does not
+    requires_static(e);
+
+    let l = late_bound;
+    // this correctly does not error
+    requires_static(l);
+}
+```
+
+## Requirements for a parameter to be late bound
+
+### Must be a lifetime parameter
+
+Type and Const parameters are not able to be late bound as we do not have a way to support types such as `dyn for<T> Fn(Box<T>)` or `for<T> fn(Box<T>)`. Calling such types requires being able to monomorphize the underlying function which is not possible with indirection through dynamic dispatch.
+
+### Must not be used in a where clause
+
+Currently when a generic parameter is used in a where clause it must be early bound. For example:
+```rust
+# trait Trait<'a> {}
+fn foo<'a, T: Trait<'a>>(_: &'a String, _: T) {}
+```
+
+In this example the lifetime parameter `'a` is considered to be early bound as it appears in the where clause `T: Trait<'a>`. This is true even for "trivial" where clauses such as `'a: 'a` or those implied by wellformedness of function arguments, for example:
+```rust
+fn foo<'a: 'a>(_: &'a String) {}
+fn bar<'a, T: 'a>(_: &'a T) {}
+```
+
+In both of these functions the lifetime parameter `'a` would be considered to be early bound even though the where clauses they are used in arguably do not actually impose any constraints on the caller.
+
+The reason for this restriction is a combination of two things:
+- We cannot prove bounds on late bound parameters until they have been instantiated
+- Function pointers and trait objects do not have a way to represent yet to be proven where clauses from the underlying function
+
+Take the following example:
+```rust
+trait Trait<'a> {}
+fn foo<'a, T: Trait<'a>>(_: &'a T) {}
+
+let f = foo::<String>;
+let f = f as for<'a> fn(&'a String);
+f(&String::new());
+```
+
+At *some point* during type checking an error should be emitted for this code as `String` does not implement `Trait` for any lifetime.
+
+If the lifetime `'a` were late bound then this becomes difficult to check. When naming `foo` we do not know what lifetime should be used as part of the `T: Trait<'a>` trait bound as it has not yet been instantiated. When coercing the function item type to a function pointer we have no way of tracking the `String: Trait<'a>` trait bound that must be proven when calling the function. 
+
+If the lifetime `'a` is early bound (which it is in the current implementation in rustc), then the trait bound can be checked when naming the function `foo`. Requiring parameters used in where clauses to be early bound gives a natural place to check where clauses defined on the function.
+
+Finally, we do not require lifetimes to be early bound if they are used in *implied bounds*, for example:
+```rust
+fn foo<'a, T>(_: &'a T) {}
+
+let f = foo;
+f(&String::new());
+f(&String::new());
+```
+
+This code compiles, demonstrating that the lifetime parameter is late bound, even though `'a` is used in the type `&'a T` which implicitly requires `T: 'a` to hold. Implied bounds can be treated specially as any types introducing implied bounds are in the signature of the function pointer type, which means that when calling the function we know to prove `T: 'a`.
+
+### Must be constrained by argument types
+
+It is important that builtin impls on function item types do not wind up with unconstrained generic parameters as this can lead to unsoundness. This is the same kind of restriction as applies to user written impls, for example the following code results in an error:
+```rust
+trait Trait {
+    type Assoc;
+}
+
+impl<'a> Trait for u8 {
+    type Assoc = &'a String;
+}
+```
+
+The analogous example for builtin impls on function items would be the following:
+```rust,ignore
+fn foo<'a>() -> &'a String { /* ... */ }
+```
+If the lifetime parameter `'a` were to be late bound we would wind up with a builtin impl with an unconstrained lifetime, we can manually write out the desugaring for the function item type and its impls with `'a` being late bound to demonstrate this:
+```rust,ignore
+// NOTE: this is just for demonstration, in practice `'a` is early bound
+struct FooFnItem;
+
+impl<'a> Fn<()> for FooFnItem {
+    type Output = &'a String;
+    /* fn call(...) -> ... { ... } */
+}
+```
+
+In order to avoid such a situation we consider `'a` to be early bound which causes the lifetime on the impl to be constrained by the self type:
+```rust,ignore
+struct FooFnItem<'a>(PhantomData<fn() -> &'a String>);
+
+impl<'a> Fn<()> for FooFnItem<'a> {
+    type Output = &'a String;
+    /* fn call(...) -> ... { ... } */
+}
+```
\ No newline at end of file
diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md
index 533f7eb5e73..a7ab3d773ac 100644
--- a/src/doc/rustc-dev-guide/src/external-repos.md
+++ b/src/doc/rustc-dev-guide/src/external-repos.md
@@ -3,24 +3,24 @@
 The `rust-lang/rust` git repository depends on several other repos in the `rust-lang` organization.
 There are three main ways we use dependencies:
 1. As a Cargo dependency through crates.io (e.g. `rustc-rayon`)
-2. As a git subtree (e.g. `clippy`)
+2. As a git (e.g. `clippy`) or a [josh] (e.g. `miri`) subtree
 3. As a git submodule (e.g. `cargo`)
 
-As a general rule, use crates.io for libraries that could be useful for others in the ecosystem; use
-subtrees for tools that depend on compiler internals and need to be updated if there are breaking
-changes; and use submodules for tools that are independent of the compiler.
+As a general rule:
+- Use crates.io for libraries that could be useful for others in the ecosystem
+- Use subtrees for tools that depend on compiler internals and need to be updated if there are breaking
+changes
+- Use submodules for tools that are independent of the compiler
 
-## External Dependencies (subtree)
+## External Dependencies (subtrees)
 
-As a developer to this repository, you don't have to treat the following external projects
-differently from other crates that are directly in this repo:
+The following external projects are managed using some form of a `subtree`:
 
-* [Clippy](https://github.com/rust-lang/rust-clippy)
-* [Miri]
+* [clippy](https://github.com/rust-lang/rust-clippy)
+* [miri](https://github.com/rust-lang/miri)
 * [rustfmt](https://github.com/rust-lang/rustfmt)
 * [rust-analyzer](https://github.com/rust-lang/rust-analyzer)
-
-[Miri]: https://github.com/rust-lang/miri
+* [rustc_codegen_cranelift](https://github.com/rust-lang/rustc_codegen_cranelift)
 
 In contrast to `submodule` dependencies
 (see below for those), the `subtree` dependencies are just regular files and directories which can
@@ -29,6 +29,20 @@ to these tools should be filed against the tools directly in their respective
 upstream repositories. The exception is that when rustc changes are required to
 implement a new tool feature or test, that should happen in one collective rustc PR.
 
+`subtree` dependencies are currently managed by two distinct approaches:
+
+* Using `git subtree`
+  * `clippy` ([sync guide](https://doc.rust-lang.org/nightly/clippy/development/infrastructure/sync.html#performing-the-sync-from-rust-langrust-to-clippy))
+  * `rustfmt`
+  * `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7))
+* Using the [josh] tool
+  * `miri` ([sync guide](https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#advanced-topic-syncing-with-the-rustc-repo))
+  * `rust-analyzer` ([sync script](https://github.com/rust-lang/rust-analyzer/blob/2e13684be123eca7181aa48e043e185d8044a84a/xtask/src/release.rs#L147))
+
+The [josh] tool is an alternative to git subtrees, which manages git history in a different way and scales better to larger repositories. Specific tooling is required to work with josh, you can check out the `miri` or `rust-analyzer` scripts linked above for inspiration. If you want to migrate a subtree from `git subtree` to josh, you can check out [this guide](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg).
+
+Below you can find a guide on how to perform push and pull synchronization with the main rustc repo using `git subtree`, although these instructions might differ repo from repo.
+
 ### Synchronizing a subtree
 
 Periodically the changes made to subtree based dependencies need to be synchronized between this
@@ -84,7 +98,6 @@ Now you're done, the `src/tools/clippy` directory behaves as if Clippy were
 part of the rustc monorepo, so no one but you (or others that synchronize
 subtrees) actually needs to use `git subtree`.
 
-
 ## External Dependencies (submodules)
 
 Building Rust will also use external git repositories tracked using [git
@@ -111,3 +124,4 @@ the week leading up to the beta cut.
 [The Rust Reference]: https://github.com/rust-lang/reference/
 [toolstate website]: https://rust-lang-nursery.github.io/rust-toolstate/
 [Toolstate chapter]: https://forge.rust-lang.org/infra/toolstate.html
+[josh]: https://josh-project.github.io/josh/intro.html
diff --git a/src/doc/rustc-dev-guide/src/generic_parameters_summary.md b/src/doc/rustc-dev-guide/src/generic_parameters_summary.md
index 3403c9f2991..da38ba0455c 100644
--- a/src/doc/rustc-dev-guide/src/generic_parameters_summary.md
+++ b/src/doc/rustc-dev-guide/src/generic_parameters_summary.md
@@ -25,42 +25,4 @@ Interestingly, `ty::Generics` does not currently contain _every_ generic paramet
 [ch_representing_types]: ./ty.md
 [`ty::Generics`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Generics.html
 [`GenericParamDef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/generics/struct.GenericParamDef.html
-
-# Early vs Late bound parameters
-
-
-```rust
-fn foo<'a, T>(b: &'a T) -> &'a T { b }
-//     ^^  ^early bound
-//     ^^
-//     ^^late bound
-```
-
-Generally when referring to an item with generic parameters you must specify a list of generic arguments corresponding to the item's generic parameters. In some cases it is permitted to elide these arguments but still, implicitly, a set of arguments are provided (e.g. `Vec::default()` desugars to `Vec::<_>::default()`).
-
-For functions this is not necessarily the case, for example if we take the function `foo` from the example above and write the following code:
-```rust
-fn main() {
-    let f = foo::<_>;
-
-    let b = String::new();
-    let c = String::new();
-    
-    f(&b);
-    drop(b);
-    f(&c);
-}
-```
-
-This code compiles perfectly fine even though there is no single lifetime that could possibly be specified in `foo::<_>` that would allow for both
-the `&b` and `&c` borrows to be used as arguments (note: the `drop(b)` line forces the `&b` borrow to be shorter than the `&c` borrow). This works because the `'a` lifetime is _late bound_.
-
-A generic parameter being late bound means that when we write `foo::<_>` we do not actually provide an argument for that parameter, instead we wait until _calling_ the function to provide the generic argument. In the above example this means that we are doing something like `f::<'_>(&b);` and `f::<'_>(&c);` (although in practice we do not actually support turbofishing late bound parameters in this manner)
-
-It may be helpful to think of "early bound parameter" or "late bound parameter" as meaning "early provided parameter" and "late provided parameter", i.e. we provide the argument to the parameter either early (when naming the function) or late (when calling it).
-
-Late bound parameters on functions are tracked with a [`Binder`] when accessing the signature of the function, this can be done with the [`fn_sig`] query. For more information of binders see the [chapter on `Binder`s ][ch_binders].
-
-[`Binder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.Binder.html
-[`fn_sig`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.fn_sig
-[ch_binders]: ./ty_module/binders.md
\ No newline at end of file
+[ch_binders]: ./ty_module/binders.md
diff --git a/src/doc/rustc-dev-guide/src/method-lookup.md b/src/doc/rustc-dev-guide/src/method-lookup.md
index 8b49e8d004b..c8d529a32b5 100644
--- a/src/doc/rustc-dev-guide/src/method-lookup.md
+++ b/src/doc/rustc-dev-guide/src/method-lookup.md
@@ -67,6 +67,7 @@ imported to use an inherent method, they are associated with the type
 itself (note that inherent impls can only be defined in the same
 crate as the type itself).
 
+<!--
 FIXME: Inherent candidates are not always derived from impls.  If you
 have a trait object, such as a value of type `Box<ToString>`, then the
 trait methods (`to_string()`, in this case) are inherently associated
@@ -76,7 +77,8 @@ to change: when DST's "impl Trait for Trait" is complete, trait object
 dispatch could be subsumed into trait matching, and the type parameter
 behavior should be reconsidered in light of where clauses.
 
-TODO: Is this FIXME still accurate?
+Is this still accurate?
+-->
 
 **Extension candidates** are derived from imported traits.  If I have
 the trait `ToString` imported, and I call `to_string()` as a method,
diff --git a/src/doc/rustc-dev-guide/src/solve/normalization.md b/src/doc/rustc-dev-guide/src/solve/normalization.md
index 8858258b542..99dc20c46b5 100644
--- a/src/doc/rustc-dev-guide/src/solve/normalization.md
+++ b/src/doc/rustc-dev-guide/src/solve/normalization.md
@@ -1,5 +1,7 @@
 # Normalization in the new solver
 
+> FIXME: Normalization has been changed significantly since this chapter was written.
+
 With the new solver we've made some fairly significant changes to normalization when compared
 to the existing implementation.
 
@@ -52,12 +54,14 @@ before assigning the resulting rigid type to an inference variable. This is used
 This has to be used whenever we match on the value of some type, both inside
 and outside of the trait solver.
 
+<!--
 FIXME: structure, maybe we should have an "alias handling" chapter instead as
 talking about normalization without explaining that doesn't make too much
 sense.
 
 FIXME: it is likely that this will subtly change again by mostly moving structural
 normalization into `NormalizesTo`.
+-->
 
 [structural_norm]: https://github.com/rust-lang/rust/blob/2627e9f3012a97d3136b3e11bf6bd0853c38a534/compiler/rustc_trait_selection/src/solve/alias_relate.rs#L140-L175
 [structural-relate]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_trait_selection/src/solve/alias_relate.rs#L88-L107
@@ -72,11 +76,13 @@ possible. However, this only works for aliases referencing bound variables if th
 not ambiguous as we're unable to replace the alias with a corresponding inference
 variable without leaking universes.
 
+<!--
 FIXME: we previously had to also be careful about instantiating the new inference
 variable with another normalizeable alias. Due to our recent changes to generalization,
 this should not be the case anymore. Equating an inference variable with an alias
 now always uses `AliasRelate` to fully normalize the alias before instantiating the
 inference variable: [source][generalize-no-alias]
+-->
 
 [generalize-no-alias]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_infer/src/infer/relate/generalize.rs#L353-L358
 
diff --git a/src/doc/rustc-dev-guide/src/solve/opaque-types.md b/src/doc/rustc-dev-guide/src/solve/opaque-types.md
index 87531705c2d..672aab77080 100644
--- a/src/doc/rustc-dev-guide/src/solve/opaque-types.md
+++ b/src/doc/rustc-dev-guide/src/solve/opaque-types.md
@@ -60,6 +60,7 @@ Finally, we check whether the item bounds of the opaque hold for the expected ty
 [eq-prev]: https://github.com/rust-lang/rust/blob/384d26fc7e3bdd7687cc17b2662b091f6017ec2a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs#L51-L59
 [insert-storage]: https://github.com/rust-lang/rust/blob/384d26fc7e3bdd7687cc17b2662b091f6017ec2a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs#L68
 [item-bounds-ck]: https://github.com/rust-lang/rust/blob/384d26fc7e3bdd7687cc17b2662b091f6017ec2a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs#L69-L74
+
 [^1]: FIXME: this should ideally only result in a unique candidate given that we require the args to be placeholders and regions are always inference vars
 [^2]: FIXME: why do we check whether the expected type is rigid for this.
 
@@ -101,6 +102,7 @@ The handling of member constraints does not change in the new solver. See the
 
 FIXME: We need to continue to support calling methods on still unconstrained
 opaque types in their defining scope. It's unclear how to best do this.
+
 ```rust
 use std::future::Future;
 use futures::FutureExt;
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index 17106be4674..459c082906e 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -441,6 +441,46 @@ $ COMPILETEST_FORCE_STAGE0=1 x test --stage 0 tests/run-make/<test-name>
 
 Of course, some tests will not successfully *run* in this way.
 
+#### Using rust-analyzer with `rmake.rs`
+
+Like other test programs, the `rmake.rs` scripts used by run-make tests do not
+have rust-analyzer integration by default.
+
+To work around this when working on a particular test, temporarily create a
+`Cargo.toml` file in the test's directory
+(e.g. `tests/run-make/sysroot-crates-are-unstable/Cargo.toml`)
+with these contents:
+
+<div class="warning">
+Be careful not to add this `Cargo.toml` or its `Cargo.lock` to your actual PR!
+</div>
+
+```toml
+# Convince cargo that this isn't part of an enclosing workspace.
+[workspace]
+
+[package]
+name = "rmake"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+run_make_support = { path = "../../../src/tools/run-make-support" }
+
+[[bin]]
+name = "rmake"
+path = "rmake.rs"
+```
+
+Then add a corresponding entry to `"rust-analyzer.linkedProjects"`
+(e.g. in `.vscode/settings.json`):
+
+```json
+"rust-analyzer.linkedProjects": [
+  "tests/run-make/sysroot-crates-are-unstable/Cargo.toml"
+],
+```
+
 #### Using Makefiles (legacy)
 
 <div class="warning">
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index b0527da7bf5..69f4c864186 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -2,7 +2,9 @@
 
 <!-- toc -->
 
-> **FIXME(jieyouxu)** completely revise this chapter.
+<!--
+FIXME(jieyouxu) completely revise this chapter.
+-->
 
 Directives are special comments that tell compiletest how to build and interpret
 a test. They must appear before the Rust source in the test. They may also
@@ -248,10 +250,11 @@ Consider writing the test as a proper incremental test instead.
 |-------------|--------------------------------------------------------------|------------------------------------------|---------------------------|
 | `doc-flags` | Flags passed to `rustdoc` when building the test or aux file | `rustdoc`, `js-doc-test`, `rustdoc-json` | Any valid `rustdoc` flags |
 
-> **FIXME(rustdoc)**: what does `check-test-line-numbers-match` do?
->
-> Asked in
-> <https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/What.20is.20the.20.60check-test-line-numbers-match.60.20directive.3F>.
+<!--
+**FIXME(rustdoc)**: what does `check-test-line-numbers-match` do?
+Asked in
+<https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/What.20is.20the.20.60check-test-line-numbers-match.60.20directive.3F>.
+-->
 
 ### Pretty printing
 
diff --git a/src/doc/rustc-dev-guide/src/traits/chalk.md b/src/doc/rustc-dev-guide/src/traits/chalk.md
index 78deb367506..844f42b9879 100644
--- a/src/doc/rustc-dev-guide/src/traits/chalk.md
+++ b/src/doc/rustc-dev-guide/src/traits/chalk.md
@@ -10,7 +10,7 @@ stream and say hello!
 [Types team]: https://github.com/rust-lang/types-team
 [`#t-types`]: https://rust-lang.zulipchat.com/#narrow/stream/144729-t-types
 
-The new-style trait solver is based on the work done in [chalk][chalk]. Chalk
+The new-style trait solver is based on the work done in [chalk]. Chalk
 recasts Rust's trait system explicitly in terms of logic programming. It does
 this by "lowering" Rust code into a kind of logic program we can then execute
 queries against.
@@ -30,7 +30,7 @@ You can read more about chalk itself in the
 ## Ongoing work
 The design of the new-style trait solving happens in two places:
 
-**chalk**. The [chalk][chalk] repository is where we experiment with new ideas
+**chalk**. The [chalk] repository is where we experiment with new ideas
 and designs for the trait system.
 
 **rustc**. Once we are happy with the logical rules, we proceed to
diff --git a/src/doc/rustc-dev-guide/src/ty_module/early_binder.md b/src/doc/rustc-dev-guide/src/ty_module/early_binder.md
index 69db189350f..e8ff3a53078 100644
--- a/src/doc/rustc-dev-guide/src/ty_module/early_binder.md
+++ b/src/doc/rustc-dev-guide/src/ty_module/early_binder.md
@@ -47,10 +47,10 @@ fn bar(foo: Foo<u32, f32>) {
 
 In the compiler the `instantiate` call for this is done in [`FieldDef::ty`] ([src][field_def_ty_src]), at some point during type checking `bar` we will wind up calling `FieldDef::ty(x, &[u32, f32])` in order to obtain the type of `foo.x`.
 
-**Note on indices:** It is possible for the indices in `Param` to not match with what the `EarlyBinder` binds. For
-example, the index could be out of bounds or it could be the index of a lifetime when we were expecting a type.
-These sorts of errors would be caught earlier in the compiler when translating from a `rustc_hir::Ty` to a `ty::Ty`.
-If they occur later, that is a compiler bug.
+**Note on indices:** It is a bug if the index of a `Param` does not match what the `EarlyBinder` binds. For
+example, if the index is out of bounds or the index index of a lifetime corresponds to a type parameter.
+These sorts of errors are caught earlier in the compiler during name resolution where we disallow references
+to generics parameters introduced by items that should not be nameable by the inner item. 
 
 [`FieldDef::ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.FieldDef.html#method.ty
 [field_def_ty_src]: https://github.com/rust-lang/rust/blob/44d679b9021f03a79133021b94e6d23e9b55b3ab/compiler/rustc_middle/src/ty/mod.rs#L1421-L1426
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index f0c3720eae1..01fabfb39a7 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -62,6 +62,7 @@
     - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
     - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md)
     - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md)
+    - [mips\*-mti-none-elf](platform-support/mips-mti-none-elf.md)
     - [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md)
     - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
     - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md)
@@ -87,6 +88,7 @@
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [*-unknown-redox](platform-support/redox.md)
     - [\*-unknown-uefi](platform-support/unknown-uefi.md)
+    - [\*-uwp-windows-msvc](platform-support/uwp-windows-msvc.md)
     - [\*-wrs-vxworks](platform-support/vxworks.md)
     - [wasm32-wasip1](platform-support/wasm32-wasip1.md)
     - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 24e9a3c8121..1d202402288 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -264,7 +264,7 @@ target | std | host | notes
 [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ |  | ARM64 Redox OS
 [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? |  | ARM64 TEEOS |
 [`aarch64-unknown-trusty`](platform-support/trusty.md) | ? |  |
-`aarch64-uwp-windows-msvc` | ✓ |  |
+[`aarch64-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ |  |
 [`aarch64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | ARM64 VxWorks OS
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
@@ -312,7 +312,7 @@ target | std | host | notes
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI]
 [`i686-unknown-redox`](platform-support/redox.md) | ✓ |  | i686 Redox OS
 `i686-uwp-windows-gnu` | ✓ |  | [^x86_32-floats-return-ABI]
-`i686-uwp-windows-msvc` | ✓ |  | [^x86_32-floats-return-ABI]
+[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ |  | [^x86_32-floats-return-ABI]
 [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
 [`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | [^x86_32-floats-return-ABI]
 [`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ |   | LoongArch64 OpenHarmony
@@ -332,6 +332,8 @@ target | std | host | notes
 `mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
 [`mipsel-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | 32-bit MIPS (LE), requires mips32 cpu support
 `mipsel-unknown-none` | * |  | Bare MIPS (LE) softfloat
+[`mips-mti-none-elf`](platform-support/mips-mti-none-elf.md) | * |  | Bare MIPS32r2 (BE) softfloat
+[`mipsel-mti-none-elf`](platform-support/mips-mti-none-elf.md) | * |  | Bare MIPS32r2 (LE) softfloat
 [`mipsisa32r6-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? |  | 32-bit MIPS Release 6 Big Endian
 [`mipsisa32r6el-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? |  | 32-bit MIPS Release 6 Little Endian
 [`mipsisa64r6-unknown-linux-gnuabi64`](platform-support/mips-release-6.md) | ? |  | 64-bit MIPS Release 6 Big Endian
@@ -383,8 +385,8 @@ target | std | host | notes
 [`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Thumb-mode Bare Armv4T
 [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Thumb-mode Bare Armv5TE
 [`thumbv6m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv6M with NuttX
-`thumbv7a-pc-windows-msvc` | ✓ |  |
-`thumbv7a-uwp-windows-msvc` | ✓ |  |
+`thumbv7a-pc-windows-msvc` |  |  |
+[`thumbv7a-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) |  |  |
 [`thumbv7em-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX
 [`thumbv7em-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX, hardfloat
 [`thumbv7m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7M with NuttX
@@ -406,7 +408,7 @@ target | std | host | notes
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 [`x86_64-unknown-trusty`](platform-support/trusty.md) | ? |  |
 `x86_64-uwp-windows-gnu` | ✓ |  |
-`x86_64-uwp-windows-msvc` | ✓ |  |
+[`x86_64-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ |  |
 [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 64-bit Windows 7 support
 [`x86_64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
diff --git a/src/doc/rustc/src/platform-support/mips-mti-none-elf.md b/src/doc/rustc/src/platform-support/mips-mti-none-elf.md
new file mode 100644
index 00000000000..731f0a8c42f
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/mips-mti-none-elf.md
@@ -0,0 +1,31 @@
+# `mips*-mti-none-elf`
+
+**Tier: 3**
+
+MIPS32r2 baremetal softfloat, Big Endian or Little Endian.
+
+- mips-mti-none-elf
+- mipsel-mti-none-elf
+
+## Target maintainers
+
+- YunQiang Su, `syq@debian.org`, https://github.com/wzssyqa
+
+## Background
+
+These 2 targets, aka mips-mti-none-elf and mipsel-mti-none-elf, are for
+baremetal development of MIPS32r2. The lld is used instead of Gnu-ld.
+
+## Requirements
+
+The target only supports cross compilation and no host tools. The target
+supports `alloc` with a default allocator while only support `no-std` development.
+
+The vendor name `mti` follows the naming of gcc to indicate MIPS32r2.
+
+## Cross-compilation toolchains and C code
+
+Compatible C code can be built for this target on any compiler that has a MIPS32r2
+target.  On clang and ld.lld linker, it can be generated using the
+`-march=mips`/`-march=mipsel`, `-mabi=32` with llvm features flag
+`features=+mips32r2,+soft-float,+noabicalls`.
diff --git a/src/doc/rustc/src/platform-support/uwp-windows-msvc.md b/src/doc/rustc/src/platform-support/uwp-windows-msvc.md
new file mode 100644
index 00000000000..ce2ebb686fa
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/uwp-windows-msvc.md
@@ -0,0 +1,52 @@
+# `x86_64-uwp-windows-msvc`, `i686-uwp-windows-msvc`, `thumbv7a-uwp-windows-msvc` and `aarch64-uwp-windows-msvc`
+
+**Tier: 3**
+
+Windows targets for Universal Windows Platform (UWP) applications, using MSVC toolchain.
+
+## Target maintainers
+
+- [@bdbai](https://github.com/bdbai)
+
+## Requirements
+
+These targets are cross-compiled with std support. The host requirement and
+binary format are the same as the corresponding non-UWP targets (i.e.
+`x86_64-pc-windows-msvc`, `i686-pc-windows-msvc`, `thumbv7a-pc-windows-msvc`
+and `aarch64-pc-windows-msvc`).
+
+## Building the targets
+
+The targets can be built by enabling them for a `rustc` build, for example:
+
+```toml
+[build]
+build-stage = 1
+target = ["x86_64-uwp-windows-msvc", "aarch64-uwp-windows-msvc"]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for these targets. To compile for
+these targets, you will either need to build Rust with the targets enabled (see
+"Building the targets" above), or build your own copy of `std` by using
+`build-std` or similar.
+
+Example of building a Rust project for x64 UWP using `build-std`:
+
+```pwsh
+cargo build -Z build-std=std,panic_abort --target x86_64-uwp-windows-msvc
+```
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+## Cross-compilation toolchains and C code
+
+In general, the toolchain target should match the corresponding non-UWP
+targets. Beware that not all Win32 APIs behave the same way in UWP, and some
+are restricted in [AppContainer](https://learn.microsoft.com/en-us/windows/win32/secauthz/appcontainer-for-legacy-applications-)
+or even not available at all. If the C code being compiled happens to use any
+of restricted or unavailable APIs, consider using allowed alternatives or
+disable certain feature sets to avoid using them.
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 561b611148a..d6ca03f7643 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -128,6 +128,8 @@ static TARGETS: &[&str] = &[
     "mipsisa64r6el-unknown-linux-gnuabi64",
     "mipsel-unknown-linux-gnu",
     "mipsel-unknown-linux-musl",
+    "mips-mti-none-elf",
+    "mipsel-mti-none-elf",
     "nvptx64-nvidia-cuda",
     "powerpc-unknown-linux-gnu",
     "powerpc64-unknown-linux-gnu",
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
index 2e3386628b4..6a6c6168a1f 100644
--- a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
@@ -1,12 +1,3 @@
-error: use of a disallowed macro `std::vec`
-  --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:16:5
-   |
-LL |     vec![1, 2, 3];
-   |     ^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::disallowed-macros` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]`
-
 error: use of a disallowed macro `serde::Serialize`
   --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:18:14
    |
@@ -14,6 +5,8 @@ LL |     #[derive(Serialize)]
    |              ^^^^^^^^^
    |
    = note: no serializing
+   = note: `-D clippy::disallowed-macros` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]`
 
 error: use of a disallowed macro `macros::attr`
   --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:31:1
@@ -47,6 +40,12 @@ error: use of a disallowed macro `std::cfg`
 LL |     cfg!(unix);
    |     ^^^^^^^^^^
 
+error: use of a disallowed macro `std::vec`
+  --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:16:5
+   |
+LL |     vec![1, 2, 3];
+   |     ^^^^^^^^^^^^^
+
 error: use of a disallowed macro `macros::expr`
   --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:21:13
    |
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 48149e3b897..8c96554738e 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -934,6 +934,9 @@ fn iter_header(
 
 impl Config {
     fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec<String>) {
+        const FORBIDDEN_REVISION_NAMES: [&str; 9] =
+            ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
+
         if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
             if self.mode == Mode::RunMake {
                 panic!("`run-make` tests do not support revisions: {}", testfile.display());
@@ -948,6 +951,15 @@ impl Config {
                         raw,
                         testfile.display()
                     );
+                } else if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt)
+                    && FORBIDDEN_REVISION_NAMES.contains(&revision.as_str())
+                {
+                    panic!(
+                        "revision name `{revision}` is not permitted in a test suite that uses `FileCheck` annotations\n\
+                         as it is confusing when used as custom `FileCheck` prefix: `{revision}` in line `{}`: {}",
+                        raw,
+                        testfile.display()
+                    );
                 }
                 existing.push(revision);
             }
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 618b66dfd4c..25bb1a5f428 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -554,6 +554,59 @@ fn test_duplicate_revisions() {
 }
 
 #[test]
+#[should_panic(
+    expected = "revision name `CHECK` is not permitted in a test suite that uses `FileCheck` annotations"
+)]
+fn test_assembly_mode_forbidden_revisions() {
+    let config = cfg().mode("assembly").build();
+    parse_rs(&config, "//@ revisions: CHECK");
+}
+
+#[test]
+#[should_panic(
+    expected = "revision name `CHECK` is not permitted in a test suite that uses `FileCheck` annotations"
+)]
+fn test_codegen_mode_forbidden_revisions() {
+    let config = cfg().mode("codegen").build();
+    parse_rs(&config, "//@ revisions: CHECK");
+}
+
+#[test]
+#[should_panic(
+    expected = "revision name `CHECK` is not permitted in a test suite that uses `FileCheck` annotations"
+)]
+fn test_miropt_mode_forbidden_revisions() {
+    let config = cfg().mode("mir-opt").build();
+    parse_rs(&config, "//@ revisions: CHECK");
+}
+
+#[test]
+fn test_forbidden_revisions_allowed_in_non_filecheck_dir() {
+    let revisions = ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
+    let modes = [
+        "pretty",
+        "debuginfo",
+        "rustdoc",
+        "rustdoc-json",
+        "codegen-units",
+        "incremental",
+        "ui",
+        "js-doc-test",
+        "coverage-map",
+        "coverage-run",
+        "crashes",
+    ];
+
+    for rev in revisions {
+        let content = format!("//@ revisions: {rev}");
+        for mode in modes {
+            let config = cfg().mode(mode).build();
+            parse_rs(&config, &content);
+        }
+    }
+}
+
+#[test]
 fn ignore_arch() {
     let archs = [
         ("x86_64-unknown-linux-gnu", "x86_64"),
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 1f98e820840..b5b360db252 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -138,9 +138,9 @@ dependencies = [
 
 [[package]]
 name = "bstr"
-version = "1.11.1"
+version = "1.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8"
+checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
 dependencies = [
  "memchr",
  "regex-automata",
@@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.2.6"
+version = "1.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
+checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
 dependencies = [
  "shlex",
 ]
@@ -1446,9 +1446,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.93"
+version = "2.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
+checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1488,12 +1488,13 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.14.0"
+version = "3.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
+checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
 dependencies = [
  "cfg-if",
  "fastrand",
+ "getrandom",
  "once_cell",
  "rustix",
  "windows-sys",
@@ -1881,9 +1882,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.6.20"
+version = "0.6.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
 dependencies = [
  "memchr",
 ]
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index d00d5a9b4da..b71ce92771a 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -18,7 +18,7 @@ const LICENSES: &[&str] = &[
     // tidy-alphabetical-start
     "(MIT OR Apache-2.0) AND Unicode-3.0",                 // unicode_ident (1.0.14)
     "(MIT OR Apache-2.0) AND Unicode-DFS-2016",            // unicode_ident (1.0.12)
-    "0BSD OR MIT OR Apache-2.0",                           // adler license
+    "0BSD OR MIT OR Apache-2.0",                           // adler2 license
     "0BSD",
     "Apache-2.0 / MIT",
     "Apache-2.0 OR ISC OR MIT",
@@ -195,6 +195,7 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     ("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
+    ("foldhash", "Zlib"),
     ("mach2", "BSD-2-Clause OR MIT OR Apache-2.0"),
     ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
     ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
@@ -462,7 +463,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
 const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
     "addr2line",
-    "adler",
+    "adler2",
     "allocator-api2",
     "cc",
     "cfg-if",
@@ -502,7 +503,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[
 
 const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
-    "ahash",
+    "allocator-api2",
     "anyhow",
     "arbitrary",
     "bitflags",
@@ -524,6 +525,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "crc32fast",
     "equivalent",
     "fallible-iterator",
+    "foldhash",
     "gimli",
     "hashbrown",
     "indexmap",
@@ -533,7 +535,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "mach2",
     "memchr",
     "object",
-    "once_cell",
     "proc-macro2",
     "quote",
     "regalloc2",
@@ -541,13 +542,11 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "rustc-hash",
     "serde",
     "serde_derive",
-    "slice-group-by",
     "smallvec",
     "stable_deref_trait",
     "syn",
     "target-lexicon",
     "unicode-ident",
-    "version_check",
     "wasmtime-jit-icache-coherence",
     "windows-sys",
     "windows-targets",
@@ -559,8 +558,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "windows_x86_64_gnu",
     "windows_x86_64_gnullvm",
     "windows_x86_64_msvc",
-    "zerocopy",
-    "zerocopy-derive",
     // tidy-alphabetical-end
 ];
 
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 7d50647bed1..69b42de9e10 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -285,6 +285,12 @@
 //@ revisions: mips_unknown_linux_uclibc
 //@ [mips_unknown_linux_uclibc] compile-flags: --target mips-unknown-linux-uclibc
 //@ [mips_unknown_linux_uclibc] needs-llvm-components: mips
+//@ revisions: mips_mti_none_elf
+//@ [mips_mti_none_elf] compile-flags: --target mips-mti-none-elf
+//@ [mips_mti_none_elf] needs-llvm-components: mips
+//@ revisions: mipsel_mti_none_elf
+//@ [mipsel_mti_none_elf] compile-flags: --target mipsel-mti-none-elf
+//@ [mipsel_mti_none_elf] needs-llvm-components: mips
 //@ revisions: mipsel_sony_psp
 //@ [mipsel_sony_psp] compile-flags: --target mipsel-sony-psp
 //@ [mipsel_sony_psp] needs-llvm-components: mips
@@ -676,6 +682,8 @@
 #[lang = "sized"]
 trait Sized {}
 
+// Force linkage to ensure code is actually generated
+#[no_mangle]
 pub fn test() -> u8 {
     42
 }
diff --git a/tests/assembly/targets/targets-macho.rs b/tests/assembly/targets/targets-macho.rs
index 8095ae9029b..25e9059afeb 100644
--- a/tests/assembly/targets/targets-macho.rs
+++ b/tests/assembly/targets/targets-macho.rs
@@ -83,6 +83,8 @@
 #[lang = "sized"]
 trait Sized {}
 
+// Force linkage to ensure code is actually generated
+#[no_mangle]
 pub fn test() -> u8 {
     42
 }
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
index f38a1ae72de..e7f70a1e24a 100644
--- a/tests/codegen/target-feature-overrides.rs
+++ b/tests/codegen/target-feature-overrides.rs
@@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
 }
 
 // CHECK: attributes [[APPLEATTRS]]
-// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
+// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx,+avx,{{.*}}"
 // CHECK: attributes [[BANANAATTRS]]
-// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="-avx2,-avx"
+// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx"
diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs
index 1b2b63c3d1a..6daa5cd7d5e 100644
--- a/tests/codegen/tied-features-strength.rs
+++ b/tests/codegen/tied-features-strength.rs
@@ -11,10 +11,11 @@
 // ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
 
 //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
-// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?))*}}" }
+// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
 
 //@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
-// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-fp-armv8,?)|(-neon,?))*}}" }
+// `neon` and `fp-armv8` get enabled as target base features, but then disabled again at the end of the list.
+// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}},-neon,-fp-armv8{{(,\+fpmr)?}}" }
 
 //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+fp-armv8,?)|(\+neon,?))*}}" }
diff --git a/tests/crashes/134336.rs b/tests/crashes/134336.rs
new file mode 100644
index 00000000000..14b88e14f04
--- /dev/null
+++ b/tests/crashes/134336.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #134336
+#![expect(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+trait Tr {
+    fn f();
+}
+
+fn g<T: Tr>() {
+    become T::f();
+}
diff --git a/tests/crashes/134355.rs b/tests/crashes/134355.rs
new file mode 100644
index 00000000000..b662341e6b1
--- /dev/null
+++ b/tests/crashes/134355.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #134355
+
+//@compile-flags: --crate-type=lib
+fn digit() -> str {
+    return { i32::MIN };
+}
diff --git a/tests/crashes/134479.rs b/tests/crashes/134479.rs
new file mode 100644
index 00000000000..0e4ddb2bfd5
--- /dev/null
+++ b/tests/crashes/134479.rs
@@ -0,0 +1,24 @@
+//@ known-bug: #134479
+//@ compile-flags: -Csymbol-mangling-version=v0 -Cdebuginfo=1
+
+#![feature(generic_const_exprs)]
+
+fn main() {
+    test::<2>();
+}
+
+struct Test<const N: usize>;
+
+fn new<const N: usize>() -> Test<N>
+where
+    [(); N * 1]: Sized,
+{
+    Test
+}
+
+fn test<const N: usize>() -> Test<{ N - 1 }>
+where
+    [(); (N - 1) * 1]: Sized,
+{
+    new()
+}
diff --git a/tests/crashes/134587.rs b/tests/crashes/134587.rs
new file mode 100644
index 00000000000..6d4441012e0
--- /dev/null
+++ b/tests/crashes/134587.rs
@@ -0,0 +1,27 @@
+//@ known-bug: #134587
+
+use std::ops::Add;
+
+pub fn foo<T>(slf: *const T)
+where
+    *const T: Add,
+{
+    slf + slf;
+}
+
+pub fn foo2<T>(slf: *const T)
+where
+    *const T: Add<u8>,
+{
+    slf + 1_u8;
+}
+
+
+pub trait TimesTwo
+   where *const Self: Add<*const Self>,
+{
+   extern "C" fn t2_ptr(slf: *const Self)
+   -> <*const Self as Add<*const Self>>::Output {
+       slf + slf
+   }
+}
diff --git a/tests/crashes/134615.rs b/tests/crashes/134615.rs
new file mode 100644
index 00000000000..d7aa51389a0
--- /dev/null
+++ b/tests/crashes/134615.rs
@@ -0,0 +1,16 @@
+//@ known-bug: #134615
+
+#![feature(generic_const_exprs)]
+
+trait Trait {
+    const CONST: usize;
+}
+
+fn f()
+where
+    for<'a> (): Trait,
+    [(); <() as Trait>::CONST]:,
+{
+}
+
+pub fn main() {}
diff --git a/tests/crashes/134641.rs b/tests/crashes/134641.rs
new file mode 100644
index 00000000000..e3e5ab69287
--- /dev/null
+++ b/tests/crashes/134641.rs
@@ -0,0 +1,13 @@
+//@ known-bug: #134641
+#![feature(associated_const_equality)]
+
+pub trait IsVoid {
+    const IS_VOID: bool;
+}
+impl IsVoid for () {
+    const IS_VOID: bool = true;
+}
+
+pub trait Maybe {}
+impl Maybe for () {}
+impl Maybe for () where (): IsVoid<IS_VOID = true> {}
diff --git a/tests/crashes/134654.rs b/tests/crashes/134654.rs
new file mode 100644
index 00000000000..8a8d18359e9
--- /dev/null
+++ b/tests/crashes/134654.rs
@@ -0,0 +1,12 @@
+//@ known-bug: #134654
+//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir
+//@ only-x86_64
+
+fn function_with_bytes<const BYTES:
+    &'static [u8; 0xa9008fb6c9d81e42_0e25730562a601c8_u128]>() -> &'static [u8] {
+    BYTES
+}
+
+fn main() {
+    function_with_bytes::<b"aa">() == &[];
+}
diff --git a/tests/crashes/134838.rs b/tests/crashes/134838.rs
new file mode 100644
index 00000000000..ac8af09b31b
--- /dev/null
+++ b/tests/crashes/134838.rs
@@ -0,0 +1,14 @@
+//@ known-bug: #134838
+#![feature(type_ascription)]
+#![allow(dead_code)]
+
+struct Ty(());
+
+fn mk() -> impl Sized {
+    if false {
+         let _ = type_ascribe!(mk(), Ty).0;
+    }
+    Ty(())
+}
+
+fn main() {}
diff --git a/tests/crashes/134905.rs b/tests/crashes/134905.rs
new file mode 100644
index 00000000000..9f0f0f4b3f2
--- /dev/null
+++ b/tests/crashes/134905.rs
@@ -0,0 +1,16 @@
+//@ known-bug: #134905
+
+trait Iterate<'a> {
+    type Ty: Valid;
+}
+impl<'a, T> Iterate<'a> for T
+where
+    T: Check,
+{
+    default type Ty = ();
+}
+
+trait Check {}
+impl<'a, T> Eq for T where <T as Iterate<'a>>::Ty: Valid {}
+
+trait Valid {}
diff --git a/tests/crashes/135020.rs b/tests/crashes/135020.rs
new file mode 100644
index 00000000000..b44056eb3af
--- /dev/null
+++ b/tests/crashes/135020.rs
@@ -0,0 +1,11 @@
+//@ known-bug: #135020
+
+pub fn problem_thingy(items: &mut impl Iterator<Item = str>) {
+    let mut peeker = items.peekable();
+    match peeker.peek() {
+        Some(_) => (),
+        None => return (),
+    }
+}
+
+pub fn main() {}
diff --git a/tests/crashes/135039.rs b/tests/crashes/135039.rs
new file mode 100644
index 00000000000..c4c5336fd4f
--- /dev/null
+++ b/tests/crashes/135039.rs
@@ -0,0 +1,34 @@
+//@ known-bug: #135039
+//@ edition:2021
+
+pub type UserId<Backend> = <<Backend as AuthnBackend>::User as AuthUser>::Id;
+
+pub trait AuthUser {
+    type Id;
+}
+
+pub trait AuthnBackend {
+    type User: AuthUser;
+}
+
+pub struct AuthSession<Backend: AuthnBackend> {
+    user: Option<Backend::User>,
+    data: Option<UserId<Backend>>,
+}
+
+pub trait Authz: Sized {
+    type AuthnBackend: AuthnBackend<User = Self>;
+}
+
+pub trait Query<User: Authz> {
+    type Output;
+    async fn run(&self) -> Result<Self::Output, ()>;
+}
+
+pub async fn run_query<User: Authz, Q: Query<User> + 'static>(
+    auth: AuthSession<User::AuthnBackend>,
+    query: Q,
+) -> Result<Q::Output, ()> {
+    let user = auth.user;
+    query.run().await
+}
diff --git a/tests/mir-opt/box_expr.rs b/tests/mir-opt/box_expr.rs
index 41cd4ca57bf..233946e713c 100644
--- a/tests/mir-opt/box_expr.rs
+++ b/tests/mir-opt/box_expr.rs
@@ -1,7 +1,7 @@
 //@ test-mir-pass: ElaborateDrops
 //@ needs-unwind
 
-#![feature(rustc_attrs, stmt_expr_attributes)]
+#![feature(rustc_attrs, liballoc_internals)]
 
 // EMIT_MIR box_expr.main.ElaborateDrops.diff
 fn main() {
@@ -17,8 +17,7 @@ fn main() {
     // CHECK:   [[boxref:_.*]] = &mut [[box]];
     // CHECK:   <Box<S> as Drop>::drop(move [[boxref]])
 
-    let x = #[rustc_box]
-    Box::new(S::new());
+    let x = std::boxed::box_new(S::new());
     drop(x);
 }
 
diff --git a/tests/mir-opt/building/uniform_array_move_out.rs b/tests/mir-opt/building/uniform_array_move_out.rs
index 0682891611d..aff5996d0b6 100644
--- a/tests/mir-opt/building/uniform_array_move_out.rs
+++ b/tests/mir-opt/building/uniform_array_move_out.rs
@@ -1,25 +1,15 @@
 // skip-filecheck
-#![feature(stmt_expr_attributes, rustc_attrs)]
+#![feature(liballoc_internals, rustc_attrs)]
 
 // EMIT_MIR uniform_array_move_out.move_out_from_end.built.after.mir
 fn move_out_from_end() {
-    let a = [
-        #[rustc_box]
-        Box::new(1),
-        #[rustc_box]
-        Box::new(2),
-    ];
+    let a = [std::boxed::box_new(1), std::boxed::box_new(2)];
     let [.., _y] = a;
 }
 
 // EMIT_MIR uniform_array_move_out.move_out_by_subslice.built.after.mir
 fn move_out_by_subslice() {
-    let a = [
-        #[rustc_box]
-        Box::new(1),
-        #[rustc_box]
-        Box::new(2),
-    ];
+    let a = [std::boxed::box_new(1), std::boxed::box_new(2)];
     let [_y @ ..] = a;
 }
 
diff --git a/tests/mir-opt/const_prop/boxes.rs b/tests/mir-opt/const_prop/boxes.rs
index f04db260e27..a192d6b4133 100644
--- a/tests/mir-opt/const_prop/boxes.rs
+++ b/tests/mir-opt/const_prop/boxes.rs
@@ -2,7 +2,7 @@
 //@ compile-flags: -O
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(rustc_attrs, stmt_expr_attributes)]
+#![feature(rustc_attrs, liballoc_internals)]
 
 // Note: this test verifies that we, in fact, do not const prop `#[rustc_box]`
 
@@ -13,7 +13,5 @@ fn main() {
     // CHECK: (*{{_.*}}) = const 42_i32;
     // CHECK: [[tmp:_.*]] = copy (*{{_.*}});
     // CHECK: [[x]] = copy [[tmp]];
-    let x = *(#[rustc_box]
-    Box::new(42))
-        + 0;
+    let x = *(std::boxed::box_new(42)) + 0;
 }
diff --git a/tests/mir-opt/issue_62289.rs b/tests/mir-opt/issue_62289.rs
index 40e8352cff4..d020c2cedca 100644
--- a/tests/mir-opt/issue_62289.rs
+++ b/tests/mir-opt/issue_62289.rs
@@ -3,14 +3,11 @@
 // initializing it
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-#![feature(rustc_attrs)]
+#![feature(rustc_attrs, liballoc_internals)]
 
 // EMIT_MIR issue_62289.test.ElaborateDrops.before.mir
 fn test() -> Option<Box<u32>> {
-    Some(
-        #[rustc_box]
-        Box::new(None?),
-    )
+    Some(std::boxed::box_new(None?))
 }
 
 fn main() {
diff --git a/tests/run-make/simd-ffi/rmake.rs b/tests/run-make/simd-ffi/rmake.rs
index 04990c8bdf4..ef71dfa4c30 100644
--- a/tests/run-make/simd-ffi/rmake.rs
+++ b/tests/run-make/simd-ffi/rmake.rs
@@ -56,7 +56,7 @@ fn main() {
             .target(&target)
             .emit("llvm-ir,asm")
             .input("simd.rs")
-            .arg("-Ctarget-feature=+neon,+sse")
+            .arg("-Ctarget-feature=-soft-float,+neon,+sse")
             .arg(&format!("-Cextra-filename=-{target}"))
             .run();
     }
diff --git a/tests/ui/attributes/rustc-box.rs b/tests/ui/attributes/rustc-box.rs
deleted file mode 100644
index b3726fb3867..00000000000
--- a/tests/ui/attributes/rustc-box.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-#![feature(rustc_attrs, stmt_expr_attributes)]
-
-fn foo(_: u32, _: u32) {}
-fn bar(_: u32) {}
-
-fn main() {
-    #[rustc_box]
-    Box::new(1); // OK
-    #[rustc_box]
-    Box::pin(1); //~ ERROR `#[rustc_box]` attribute used incorrectly
-    #[rustc_box]
-    foo(1, 1); //~ ERROR `#[rustc_box]` attribute used incorrectly
-    #[rustc_box]
-    bar(1); //~ ERROR `#[rustc_box]` attribute used incorrectly
-    #[rustc_box] //~ ERROR `#[rustc_box]` attribute used incorrectly
-    #[rustfmt::skip]
-    Box::new(1);
-}
diff --git a/tests/ui/attributes/rustc-box.stderr b/tests/ui/attributes/rustc-box.stderr
deleted file mode 100644
index 073a18c7d58..00000000000
--- a/tests/ui/attributes/rustc-box.stderr
+++ /dev/null
@@ -1,34 +0,0 @@
-error: `#[rustc_box]` attribute used incorrectly
-  --> $DIR/rustc-box.rs:10:5
-   |
-LL |     Box::pin(1);
-   |     ^^^^^^^^^^^
-   |
-   = note: `#[rustc_box]` may only be applied to a `Box::new()` call
-
-error: `#[rustc_box]` attribute used incorrectly
-  --> $DIR/rustc-box.rs:12:5
-   |
-LL |     foo(1, 1);
-   |     ^^^^^^^^^
-   |
-   = note: `#[rustc_box]` may only be applied to a `Box::new()` call
-
-error: `#[rustc_box]` attribute used incorrectly
-  --> $DIR/rustc-box.rs:14:5
-   |
-LL |     bar(1);
-   |     ^^^^^^
-   |
-   = note: `#[rustc_box]` may only be applied to a `Box::new()` call
-
-error: `#[rustc_box]` attribute used incorrectly
-  --> $DIR/rustc-box.rs:15:5
-   |
-LL |     #[rustc_box]
-   |     ^^^^^^^^^^^^
-   |
-   = note: no other attributes may be applied
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
index d49ed3e7551..23b6edacce7 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
@@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `value`
 LL | #[cfg(target_vendor = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
+   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `feature`
diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
index 81dbbca4f86..804d7fb9163 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
@@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `value`
 LL | #[cfg(target_vendor = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
+   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `unk`
diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
index 81dbbca4f86..804d7fb9163 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
@@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `value`
 LL | #[cfg(target_vendor = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
+   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `unk`
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index ab69938f51a..5c1898a0ae3 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -230,7 +230,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_vendor = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
+   = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/coroutine/issue-105084.rs b/tests/ui/coroutine/issue-105084.rs
index 0f6168ec58b..cddee499017 100644
--- a/tests/ui/coroutine/issue-105084.rs
+++ b/tests/ui/coroutine/issue-105084.rs
@@ -2,7 +2,7 @@
 #![feature(coroutines)]
 #![feature(coroutine_clone)]
 #![feature(coroutine_trait)]
-#![feature(rustc_attrs, stmt_expr_attributes)]
+#![feature(rustc_attrs, stmt_expr_attributes, liballoc_internals)]
 
 use std::ops::Coroutine;
 use std::pin::Pin;
@@ -19,8 +19,7 @@ fn main() {
         // - create a Box that is ignored for trait computations;
         // - compute fields (and yields);
         // - assign to `t`.
-        let t = #[rustc_box]
-        Box::new((5, yield));
+        let t = std::boxed::box_new((5, yield));
         drop(t);
     };
 
diff --git a/tests/ui/coroutine/issue-105084.stderr b/tests/ui/coroutine/issue-105084.stderr
index 073f1fbea4c..23c1fdc5459 100644
--- a/tests/ui/coroutine/issue-105084.stderr
+++ b/tests/ui/coroutine/issue-105084.stderr
@@ -1,5 +1,5 @@
 error[E0382]: borrow of moved value: `g`
-  --> $DIR/issue-105084.rs:39:14
+  --> $DIR/issue-105084.rs:38:14
    |
 LL |     let mut g = #[coroutine]
    |         ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, which does not implement the `Copy` trait
@@ -23,7 +23,7 @@ LL |     let mut h = copy(g.clone());
    |                       ++++++++
 
 error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
-  --> $DIR/issue-105084.rs:33:17
+  --> $DIR/issue-105084.rs:32:17
    |
 LL |     || {
    |     -- within this `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
@@ -32,13 +32,13 @@ LL |     let mut h = copy(g);
    |                 ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`
    |
 note: coroutine does not implement `Copy` as this value is used across a yield
-  --> $DIR/issue-105084.rs:23:22
+  --> $DIR/issue-105084.rs:22:41
    |
-LL |         Box::new((5, yield));
-   |         -------------^^^^^--
-   |         |            |
-   |         |            yield occurs here, with `Box::new((5, yield))` maybe used later
-   |         has type `Box<(i32, ())>` which does not implement `Copy`
+LL |         let t = std::boxed::box_new((5, yield));
+   |                 ------------------------^^^^^--
+   |                 |                       |
+   |                 |                       yield occurs here, with `std::boxed::box_new((5, yield))` maybe used later
+   |                 has type `Box<(i32, ())>` which does not implement `Copy`
 note: required by a bound in `copy`
   --> $DIR/issue-105084.rs:10:12
    |
diff --git a/tests/ui/lint/unused/unused-allocation.rs b/tests/ui/lint/unused/unused-allocation.rs
index c1a6f5ceaf1..1d5727362ea 100644
--- a/tests/ui/lint/unused/unused-allocation.rs
+++ b/tests/ui/lint/unused/unused-allocation.rs
@@ -1,7 +1,5 @@
-#![feature(rustc_attrs, stmt_expr_attributes)]
 #![deny(unused_allocation)]
 
 fn main() {
-    _ = (#[rustc_box] Box::new([1])).len(); //~ error: unnecessary allocation, use `&` instead
     _ = Box::new([1]).len(); //~ error: unnecessary allocation, use `&` instead
 }
diff --git a/tests/ui/lint/unused/unused-allocation.stderr b/tests/ui/lint/unused/unused-allocation.stderr
index c9ccfbd30e5..4487395e908 100644
--- a/tests/ui/lint/unused/unused-allocation.stderr
+++ b/tests/ui/lint/unused/unused-allocation.stderr
@@ -1,20 +1,14 @@
 error: unnecessary allocation, use `&` instead
-  --> $DIR/unused-allocation.rs:5:9
+  --> $DIR/unused-allocation.rs:4:9
    |
-LL |     _ = (#[rustc_box] Box::new([1])).len();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     _ = Box::new([1]).len();
+   |         ^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/unused-allocation.rs:2:9
+  --> $DIR/unused-allocation.rs:1:9
    |
 LL | #![deny(unused_allocation)]
    |         ^^^^^^^^^^^^^^^^^
 
-error: unnecessary allocation, use `&` instead
-  --> $DIR/unused-allocation.rs:6:9
-   |
-LL |     _ = Box::new([1]).len();
-   |         ^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/vec-macro-in-pattern.rs b/tests/ui/macros/vec-macro-in-pattern.rs
index 26d7d4280fa..9b9a1edf54c 100644
--- a/tests/ui/macros/vec-macro-in-pattern.rs
+++ b/tests/ui/macros/vec-macro-in-pattern.rs
@@ -4,7 +4,9 @@
 
 fn main() {
     match Some(vec![42]) {
-        Some(vec![43]) => {} //~ ERROR expected pattern, found `#`
+        Some(vec![43]) => {} //~ ERROR expected a pattern, found a function call
+        //~| ERROR found associated function
+        //~| ERROR usage of qualified paths in this context is experimental
         _ => {}
     }
 }
diff --git a/tests/ui/macros/vec-macro-in-pattern.stderr b/tests/ui/macros/vec-macro-in-pattern.stderr
index f32a2cf8e43..71ba0ea5ad4 100644
--- a/tests/ui/macros/vec-macro-in-pattern.stderr
+++ b/tests/ui/macros/vec-macro-in-pattern.stderr
@@ -1,14 +1,33 @@
-error: expected pattern, found `#`
+error[E0532]: expected a pattern, found a function call
+  --> $DIR/vec-macro-in-pattern.rs:7:14
+   |
+LL |         Some(vec![43]) => {}
+   |              ^^^^^^^^ not a tuple struct or tuple variant
+   |
+   = note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: usage of qualified paths in this context is experimental
   --> $DIR/vec-macro-in-pattern.rs:7:14
    |
 LL |         Some(vec![43]) => {}
    |              ^^^^^^^^
-   |              |
-   |              expected pattern
-   |              in this macro invocation
-   |              this macro call doesn't expand to a pattern
    |
+   = note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0164]: expected tuple struct or tuple variant, found associated function `<[_]>::into_vec`
+  --> $DIR/vec-macro-in-pattern.rs:7:14
+   |
+LL |         Some(vec![43]) => {}
+   |              ^^^^^^^^ `fn` calls are not allowed in patterns
+   |
+   = help: for more information, visit https://doc.rust-lang.org/book/ch19-00-patterns.html
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
 
+Some errors have detailed explanations: E0164, E0532, E0658.
+For more information about an error, try `rustc --explain E0164`.
diff --git a/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr b/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr
index d5d7d7aa627..b6c3ccdedfb 100644
--- a/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr
+++ b/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr
@@ -1,4 +1,4 @@
-warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
+warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
    |
    = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs
index b3171d52c51..dab01179c0b 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs
@@ -1,11 +1,11 @@
-//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
-//@ needs-llvm-components: x86
-#![feature(no_core, lang_items)]
+//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib
+//@ needs-llvm-components: riscv
+#![feature(no_core, lang_items, riscv_target_feature)]
 #![no_core]
 
 #[lang = "sized"]
 pub trait Sized {}
 
-#[target_feature(enable = "x87")]
-//~^ERROR: cannot be toggled with
+#[target_feature(enable = "d")]
+//~^ERROR: cannot be enabled with
 pub unsafe fn my_fun() {}
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr
index 3ebbe69d8ae..9df56d86729 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr
@@ -1,8 +1,8 @@
-error: target feature `x87` cannot be toggled with `#[target_feature]`: unsound on hard-float targets because it changes float ABI
+error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
   --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:9:18
    |
-LL | #[target_feature(enable = "x87")]
-   |                  ^^^^^^^^^^^^^^
+LL | #[target_feature(enable = "d")]
+   |                  ^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs
new file mode 100644
index 00000000000..3d09217327a
--- /dev/null
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs
@@ -0,0 +1,10 @@
+//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
+//@ needs-llvm-components: x86
+//@ compile-flags: -Ctarget-feature=-sse
+// For now this is just a warning.
+//@ build-pass
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr
new file mode 100644
index 00000000000..72b2d03fe20
--- /dev/null
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr
@@ -0,0 +1,7 @@
+warning: target feature `sse` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
+   |
+   = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr
index d5d7d7aa627..b6c3ccdedfb 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr
@@ -1,4 +1,4 @@
-warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
+warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
    |
    = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr
index 604ad2f991a..6191681286a 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr
@@ -1,7 +1,11 @@
-warning: target feature `x87` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
+warning: unstable feature specified for `-Ctarget-feature`: `x87`
+   |
+   = note: this feature is not stably supported; its behavior can change in the future
+
+warning: target feature `x87` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
    |
    = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
 
-warning: 1 warning emitted
+warning: 2 warnings emitted
 
diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-target-feature-attribute.rs
index f13cdd17da6..2ba5f2215c7 100644
--- a/tests/ui/target-feature/forbidden-target-feature-attribute.rs
+++ b/tests/ui/target-feature/forbidden-target-feature-attribute.rs
@@ -7,5 +7,5 @@
 pub trait Sized {}
 
 #[target_feature(enable = "soft-float")]
-//~^ERROR: cannot be toggled with
+//~^ERROR: cannot be enabled with
 pub unsafe fn my_fun() {}
diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr
index 27ac4aaf960..f3d54cc19d3 100644
--- a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr
+++ b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr
@@ -1,4 +1,4 @@
-error: target feature `soft-float` cannot be toggled with `#[target_feature]`: unsound because it changes float ABI
+error: target feature `soft-float` cannot be enabled with `#[target_feature]`: unsound because it changes float ABI
   --> $DIR/forbidden-target-feature-attribute.rs:9:18
    |
 LL | #[target_feature(enable = "soft-float")]
diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr b/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr
index 508e1fe0cf4..797cd4be5c2 100644
--- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr
+++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr
@@ -1,4 +1,4 @@
-warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI
+warning: target feature `soft-float` cannot be disabled with `-Ctarget-feature`: unsound because it changes float ABI
    |
    = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/forbidden-target-feature-flag.stderr b/tests/ui/target-feature/forbidden-target-feature-flag.stderr
index 508e1fe0cf4..075666fbf66 100644
--- a/tests/ui/target-feature/forbidden-target-feature-flag.stderr
+++ b/tests/ui/target-feature/forbidden-target-feature-flag.stderr
@@ -1,4 +1,4 @@
-warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI
+warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: unsound because it changes float ABI
    |
    = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/unpretty/box.rs b/tests/ui/unpretty/box.rs
index 8972eccf3b8..83fdeff7a17 100644
--- a/tests/ui/unpretty/box.rs
+++ b/tests/ui/unpretty/box.rs
@@ -1,9 +1,8 @@
-//@ compile-flags: -Zunpretty=hir
+//@ compile-flags: -Zunpretty=thir-tree
 //@ check-pass
 
-#![feature(stmt_expr_attributes, rustc_attrs)]
+#![feature(liballoc_internals)]
 
 fn main() {
-    let _ = #[rustc_box]
-    Box::new(1);
+    let _ = std::boxed::box_new(1);
 }
diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout
index e3b9b9ac207..92155d0c73b 100644
--- a/tests/ui/unpretty/box.stdout
+++ b/tests/ui/unpretty/box.stdout
@@ -1,14 +1,90 @@
-//@ compile-flags: -Zunpretty=hir
-//@ check-pass
+DefId(0:3 ~ box[efb9]::main):
+params: [
+]
+body:
+    Expr {
+        ty: ()
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(11)), backwards_incompatible: None }
+        span: $DIR/box.rs:6:11: 8:2 (#0)
+        kind: 
+            Scope {
+                region_scope: Node(11)
+                lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).11))
+                value:
+                    Expr {
+                        ty: ()
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(11)), backwards_incompatible: None }
+                        span: $DIR/box.rs:6:11: 8:2 (#0)
+                        kind: 
+                            Block {
+                                targeted_by_break: false
+                                span: $DIR/box.rs:6:11: 8:2 (#0)
+                                region_scope: Node(1)
+                                safety_mode: Safe
+                                stmts: [
+                                    Stmt {
+                                        kind: Let {
+                                            remainder_scope: Remainder { block: 1, first_statement_index: 0}
+                                            init_scope: Node(2)
+                                            pattern: 
+                                                Pat: {
+                                                    ty: std::boxed::Box<i32, std::alloc::Global>
+                                                    span: $DIR/box.rs:7:9: 7:10 (#0)
+                                                    kind: PatKind {
+                                                        Wild
+                                                    }
+                                                }
+                                            ,
+                                            initializer: Some(
+                                                Expr {
+                                                    ty: std::boxed::Box<i32, std::alloc::Global>
+                                                    temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
+                                                    span: $DIR/box.rs:7:13: 7:35 (#0)
+                                                    kind: 
+                                                        Scope {
+                                                            region_scope: Node(3)
+                                                            lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).3))
+                                                            value:
+                                                                Expr {
+                                                                    ty: std::boxed::Box<i32, std::alloc::Global>
+                                                                    temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
+                                                                    span: $DIR/box.rs:7:13: 7:35 (#0)
+                                                                    kind: 
+                                                                        Box {
+                                                                            Expr {
+                                                                                ty: i32
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
+                                                                                span: $DIR/box.rs:7:33: 7:34 (#0)
+                                                                                kind: 
+                                                                                    Scope {
+                                                                                        region_scope: Node(8)
+                                                                                        lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).8))
+                                                                                        value:
+                                                                                            Expr {
+                                                                                                ty: i32
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
+                                                                                                span: $DIR/box.rs:7:33: 7:34 (#0)
+                                                                                                kind: 
+                                                                                                    Literal( lit: Spanned { node: Int(Pu128(1), Unsuffixed), span: $DIR/box.rs:7:33: 7:34 (#0) }, neg: false)
+
+                                                                                            }
+                                                                                    }
+                                                                            }
+                                                                        }
+                                                                }
+                                                        }
+                                                }
+                                            )
+                                            else_block: None
+                                            lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).9))
+                                            span: $DIR/box.rs:7:5: 7:35 (#0)
+                                        }
+                                    }
+                                ]
+                                expr: []
+                            }
+                    }
+            }
+    }
 
-#![feature(stmt_expr_attributes, rustc_attrs)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
 
-fn main() {
-    let _ =
-        #[rustc_box]
-        Box::new(1);
-}